1. 去掉在rdp的sid前填写的两个字节;2. 格式化部分代码。

feature/assist-websocket
Apex Liu 2022-06-01 11:25:49 +08:00
parent e82eecfd04
commit e9de6513eb
11 changed files with 675 additions and 609 deletions

View File

@ -692,8 +692,8 @@ class BuilderMacOS(BuilderBase):
cc.w('already exists, skip.')
def _build_openssl(self, file_name):
cc.w('skip build openssl again.')
return
# cc.w('skip build openssl again.')
# return
if not self._download_openssl(file_name):
return
@ -943,6 +943,7 @@ def main():
builder.build_jsoncpp()
builder.build_mongoose()
builder.build_zlib()
builder.build_mbedtls()
builder.build_openssl()
elif command == 'ext-server':
builder.prepare_python()

View File

@ -3,43 +3,46 @@
TsCfg g_cfg;
TsCfg::TsCfg()
{}
TsCfg::TsCfg() {}
TsCfg::~TsCfg()
{}
TsCfg::~TsCfg() {}
bool TsCfg::init(void) {
ex_astr file_content;
if(!ex_read_text_file(g_env.m_cfg_file, file_content)) {
EXLOGE("can not load config file.\n");
return false;
}
bool TsCfg::init(void)
{
ex_astr file_content;
if (!ex_read_text_file(g_env.m_cfg_file, file_content))
{
EXLOGE("can not load config file.\n");
return false;
}
if(!_load(file_content))
return false;
if (!_load(file_content))
return false;
if(!m_root.isObject()) {
if (!m_root.isObject())
{
EXLOGE("invalid config file, not in json format?\n");
return false;
}
if(m_root["file_version"].isNull()) {
if (m_root["file_version"].isNull())
{
EXLOGE("invalid config file, maybe need create new one?\n");
return false;
}
if(!m_root["file_version"].isInt()) {
if (!m_root["file_version"].isInt())
{
}
return true;
return true;
}
bool TsCfg::save(const ex_astr& new_value)
{
if(!_load(new_value))
return false;
if (!_load(new_value))
return false;
Json::StreamWriterBuilder jwb;
jwb["indentation"] = " ";
@ -49,51 +52,60 @@ bool TsCfg::save(const ex_astr& new_value)
jwriter->write(m_root, &os);
ex_astr val = os.str();
if(!ex_write_text_file(g_env.m_cfg_file, val)) {
EXLOGE("can not save config file.\n");
return false;
}
if (!ex_write_text_file(g_env.m_cfg_file, val))
{
EXLOGE("can not save config file.\n");
return false;
}
return true;
return true;
}
bool TsCfg::_parse_app(const Json::Value& m_root, const ex_astr& str_app, APP_CONFIG& cfg) {
bool TsCfg::_parse_app(const Json::Value& m_root, const ex_astr& str_app, APP_CONFIG& cfg)
{
const Json::Value& jApp = m_root[str_app.c_str()];
if(!jApp.isObject())
if (!jApp.isObject())
return false;
if (!jApp["selected"].isString()) {
if (!jApp["selected"].isString())
{
EXLOGE("invalid config, error 2.\n");
return false;
}
ex_astr _selected = jApp["selected"].asCString();;
if (!jApp["available"].isArray() || jApp["available"].size() == 0) {
if (!jApp["available"].isArray() || jApp["available"].size() == 0)
{
EXLOGE("invalid config, error 3.\n");
return false;
}
const Json::Value& jAppList = jApp["available"];
int i = 0;
for (i = 0; i < jAppList.size(); ++i) {
for (i = 0; i < jAppList.size(); ++i)
{
if (
!jAppList[i]["name"].isString()
|| !jAppList[i]["app"].isString()
|| !jAppList[i]["cmdline"].isString()
|| !jAppList[i]["desc"].isArray()
) {
!jAppList[i]["name"].isString()
|| !jAppList[i]["app"].isString()
|| !jAppList[i]["cmdline"].isString()
|| !jAppList[i]["desc"].isArray()
)
{
EXLOGE("invalid config, error 4.\n");
return false;
}
if(jAppList[i]["name"].asString().empty()) {
if (jAppList[i]["name"].asString().empty())
{
EXLOGE("invalid config, need name.\n");
return false;
}
if (jAppList[i]["display"].isNull() || jAppList[i]["display"].asString().empty()) {
if (jAppList[i]["display"].isNull() || jAppList[i]["display"].asString().empty())
{
cfg.display = jAppList[i]["name"].asCString();
} else
}
else
cfg.display = jAppList[i]["display"].asCString();
if (jAppList[i]["name"].asCString() != _selected)
@ -104,12 +116,14 @@ bool TsCfg::_parse_app(const Json::Value& m_root, const ex_astr& str_app, APP_CO
cfg.application = jAppList[i]["app"].asCString();
cfg.cmdline = jAppList[i]["cmdline"].asCString();
if(jAppList[i]["desc"].size() > 0) {
if (jAppList[i]["desc"].size() > 0)
{
const Json::Value& jAppDescList = jAppList[i]["desc"];
int j = 0;
for(j = 0; j < jAppDescList.size(); ++j) {
if(!jAppDescList[j].isString())
for (j = 0; j < jAppDescList.size(); ++j)
{
if (!jAppDescList[j].isString())
return false;
cfg.description.push_back(jAppDescList[j].asCString());
}
@ -122,28 +136,30 @@ bool TsCfg::_parse_app(const Json::Value& m_root, const ex_astr& str_app, APP_CO
}
bool TsCfg::_load(const ex_astr& str_json) {
bool TsCfg::_load(const ex_astr& str_json)
{
Json::CharReaderBuilder jcrb;
std::unique_ptr<Json::CharReader> const jreader(jcrb.newCharReader());
const char *str_json_begin = str_json.c_str();
const char* str_json_begin = str_json.c_str();
ex_astr err;
if (!jreader->parse(str_json_begin, str_json_begin + str_json.length(), &m_root, &err)) {
if (!jreader->parse(str_json_begin, str_json_begin + str_json.length(), &m_root, &err))
{
EXLOGE("can not parse new config data, not in json format? %s\n", err.c_str());
return false;
}
//===================================
// check config
//===================================
if(!_parse_app(m_root, "ssh", ssh))
//===================================
// check config
//===================================
if (!_parse_app(m_root, "ssh", ssh))
return false;
if(!_parse_app(m_root, "sftp", sftp))
if (!_parse_app(m_root, "sftp", sftp))
return false;
if(!_parse_app(m_root, "telnet", telnet))
if (!_parse_app(m_root, "telnet", telnet))
return false;
if(!_parse_app(m_root, "rdp", rdp))
if (!_parse_app(m_root, "rdp", rdp))
return false;
return true;
return true;
}

View File

@ -6,24 +6,27 @@
#include <json/json.h>
typedef struct APP_CONFIG {
typedef struct APP_CONFIG
{
ex_astr name;
ex_astr display;
ex_astr application;
ex_astr cmdline;
ex_astrs description;
}APP_CONFIG;
} APP_CONFIG;
class TsCfg
{
public:
TsCfg();
virtual ~TsCfg();
TsCfg();
virtual ~TsCfg();
bool init(void);
bool init(void);
bool save(const ex_astr& new_value);
Json::Value& get_root() {return m_root;}
Json::Value& get_root() { return m_root; }
APP_CONFIG ssh;
APP_CONFIG sftp;
@ -31,11 +34,12 @@ public:
APP_CONFIG rdp;
protected:
bool _load(const ex_astr& str_json);
bool _load(const ex_astr& str_json);
bool _parse_app(const Json::Value& m_root, const ex_astr& str_app, APP_CONFIG& cfg);
protected:
Json::Value m_root;
Json::Value m_root;
};
extern TsCfg g_cfg;

View File

@ -1,6 +1,7 @@
#include "ts_env.h"
#include <time.h>
#ifdef EX_OS_WIN32
# include <direct.h>
//# include <ShlObj.h>
@ -12,34 +13,33 @@ TsEnv g_env;
//
//=======================================================
TsEnv::TsEnv()
{}
TsEnv::TsEnv() {}
TsEnv::~TsEnv()
{}
TsEnv::~TsEnv() {}
bool TsEnv::init(const char* bundle_path, const char* cfg_file, const char* res_path, const char* log_path)
{
ex_astr2wstr(bundle_path, m_bundle_path);
ex_astr2wstr(cfg_file, m_cfg_file);
ex_astr2wstr(res_path, m_res_path);
ex_astr2wstr(res_path, m_res_path);
ex_astr2wstr(log_path, m_log_path);
#ifdef EX_DEBUG
m_site_path = L"/Users/apex/work/tp4a/teleport/client/tp_assist_macos/site";
//m_bundle_path = L"/Users/apex/work/tp4a/teleport/out/client/x64/release";
#else
m_site_path = m_res_path;
ex_path_join(m_site_path, false, L"site", NULL);
m_site_path = m_res_path;
ex_path_join(m_site_path, false, L"site", NULL);
#endif
return true;
return true;
}
extern "C" {
int mg_ssl_if_mbed_random(void *ctx, unsigned char *buf, size_t len) {
(void) ctx;
while (len--) *buf++ = (arc4random() % 255);
return 0;
int mg_ssl_if_mbed_random(void* ctx, unsigned char* buf, size_t len)
{
(void)ctx;
while (len--) { *buf++ = (arc4random() % 255); }
return 0;
}
}

View File

@ -6,25 +6,26 @@
class TsEnv
{
public:
TsEnv();
~TsEnv();
TsEnv();
bool init(const char* bundle_path, const char* cfg_file, const char* res_path, const char* log_path);
~TsEnv();
bool init(const char* bundle_path, const char* cfg_file, const char* res_path, const char* log_path);
public:
ex_wstr m_bundle_path;
ex_wstr m_cfg_file;
ex_wstr m_res_path;
ex_wstr m_cfg_file;
ex_wstr m_res_path;
// ex_wstr m_exec_file;
// ex_wstr m_exec_path;
//
// ex_wstr m_ssh_client_conf_file;
// ex_wstr m_scp_client_conf_file;
// ex_wstr m_telnet_client_conf_file;
ex_wstr m_log_path;
ex_wstr m_site_path;
// ex_wstr m_tools_path;
// ex_wstr m_exec_file;
// ex_wstr m_exec_path;
//
// ex_wstr m_ssh_client_conf_file;
// ex_wstr m_scp_client_conf_file;
// ex_wstr m_telnet_client_conf_file;
ex_wstr m_log_path;
ex_wstr m_site_path;
// ex_wstr m_tools_path;
};
extern TsEnv g_env;

View File

@ -17,23 +17,26 @@ TsHttpRpc g_http_interface;
TsHttpRpc::TsHttpRpc() : ExThreadBase("http-rpc-thread")
{
mg_mgr_init(&m_mg_mgr, NULL);
mg_mgr_init(&m_mg_mgr, NULL);
}
TsHttpRpc::~TsHttpRpc()
{
mg_mgr_free(&m_mg_mgr);
mg_mgr_free(&m_mg_mgr);
}
bool TsHttpRpc::init() {
bool TsHttpRpc::init()
{
struct mg_connection* nc = NULL;
for(int port = TS_HTTP_RPC_PORT_MIN; port < TS_HTTP_RPC_PORT_MAX; ++port) {
char addr[128] = { 0 };
for (int port = TS_HTTP_RPC_PORT_MIN; port < TS_HTTP_RPC_PORT_MAX; ++port)
{
char addr[128] = {0};
ex_strformat(addr, 128, "tcp://127.0.0.1:%d", port);
nc = mg_bind(&m_mg_mgr, addr, _mg_event_handler);
if (!nc) {
if (!nc)
{
EXLOGW("[WRN] can not start HTTP-RPC listener, maybe port %d is already in use.\n", port);
continue;
}
@ -42,7 +45,8 @@ bool TsHttpRpc::init() {
break;
}
if(m_port == 0) {
if (m_port == 0)
{
EXLOGE("[rpc] can not listen on port %d~%d\n", TS_HTTP_RPC_PORT_MIN, TS_HTTP_RPC_PORT_MAX);
return false;
}
@ -54,7 +58,8 @@ bool TsHttpRpc::init() {
return _on_init();
}
bool TsHttpRpc::_on_init() {
bool TsHttpRpc::_on_init()
{
m_content_type_map[".js"] = "application/javascript";
m_content_type_map[".png"] = "image/png";
m_content_type_map[".jpeg"] = "image/jpeg";
@ -73,258 +78,262 @@ bool TsHttpRpc::_on_init() {
void TsHttpRpc::_thread_loop(void)
{
while (!m_need_stop)
{
mg_mgr_poll(&m_mg_mgr, 500);
}
while (!m_need_stop)
{
mg_mgr_poll(&m_mg_mgr, 500);
}
EXLOGV("[core] rpc main loop end.\n");
EXLOGV("[core] rpc main loop end.\n");
}
void TsHttpRpc::_mg_event_handler(struct mg_connection *nc, int ev, void *ev_data)
void TsHttpRpc::_mg_event_handler(struct mg_connection* nc, int ev, void* ev_data)
{
struct http_message *hm = (struct http_message*)ev_data;
struct http_message* hm = (struct http_message*)ev_data;
TsHttpRpc* _this = (TsHttpRpc*)nc->user_data;
if (NULL == _this)
{
EXLOGE("[ERROR] invalid http request.\n");
return;
}
TsHttpRpc* _this = (TsHttpRpc*)nc->user_data;
if (NULL == _this)
{
EXLOGE("[ERROR] invalid http request.\n");
return;
}
switch (ev)
{
case MG_EV_HTTP_REQUEST:
{
ex_astr uri;
ex_chars _uri;
_uri.resize(hm->uri.len + 1);
memset(&_uri[0], 0, hm->uri.len + 1);
memcpy(&_uri[0], hm->uri.p, hm->uri.len);
uri = &_uri[0];
switch (ev)
{
case MG_EV_HTTP_REQUEST:
{
ex_astr uri;
ex_chars _uri;
_uri.resize(hm->uri.len + 1);
memset(&_uri[0], 0, hm->uri.len + 1);
memcpy(&_uri[0], hm->uri.p, hm->uri.len);
uri = &_uri[0];
#ifdef EX_DEBUG
const char* dbg_method = NULL;
if (hm->method.len == 3 && 0 == memcmp(hm->method.p, "GET", hm->method.len))
dbg_method = "GET";
else if (hm->method.len == 4 && 0 == memcmp(hm->method.p, "POST", hm->method.len))
dbg_method = "POST";
else
dbg_method = "UNSUPPORTED-HTTP-METHOD";
const char* dbg_method = NULL;
if (hm->method.len == 3 && 0 == memcmp(hm->method.p, "GET", hm->method.len))
dbg_method = "GET";
else if (hm->method.len == 4 && 0 == memcmp(hm->method.p, "POST", hm->method.len))
dbg_method = "POST";
else
dbg_method = "UNSUPPORTED-HTTP-METHOD";
EXLOGV("[rpc] got %s request: %s\n", dbg_method, uri.c_str());
EXLOGV("[rpc] got %s request: %s\n", dbg_method, uri.c_str());
#endif
ex_astr ret_buf;
ex_astr ret_buf;
bool b_is_html = false;
if (uri == "/") {
if (uri == "/")
{
uri = "/status.html";
b_is_html = true;
}
else if (uri == "/config") {
else if (uri == "/config")
{
uri = "/index.html";
b_is_html = true;
}
ex_astr temp;
size_t offset = uri.find("/", 1);
if (offset > 0)
{
temp = uri.substr(1, offset-1);
ex_astr temp;
size_t offset = uri.find("/", 1);
if (offset > 0)
{
temp = uri.substr(1, offset - 1);
if(temp == "api") {
ex_astr method;
ex_astr json_param;
int rv = _this->_parse_request(hm, method, json_param);
if (0 != rv)
{
EXLOGE("[ERROR] http-rpc got invalid request.\n");
_this->_create_json_ret(ret_buf, rv);
}
else
{
_this->_process_js_request(method, json_param, ret_buf);
}
if (temp == "api")
{
ex_astr method;
ex_astr json_param;
int rv = _this->_parse_request(hm, method, json_param);
if (0 != rv)
{
EXLOGE("[ERROR] http-rpc got invalid request.\n");
_this->_create_json_ret(ret_buf, rv);
}
else
{
_this->_process_js_request(method, json_param, ret_buf);
}
mg_printf(nc, "HTTP/1.0 200 OK\r\nAccess-Control-Allow-Origin: *\r\nContent-Length: %ld\r\nContent-Type: application/json\r\n\r\n%s", ret_buf.length(), ret_buf.c_str());
nc->flags |= MG_F_SEND_AND_CLOSE;
return;
}
}
mg_printf(nc, "HTTP/1.0 200 OK\r\nAccess-Control-Allow-Origin: *\r\nContent-Length: %ld\r\nContent-Type: application/json\r\n\r\n%s", ret_buf.length(), ret_buf.c_str());
nc->flags |= MG_F_SEND_AND_CLOSE;
return;
}
}
ex_astr file_suffix;
offset = uri.rfind(".");
if (offset > 0)
{
file_suffix = uri.substr(offset, uri.length());
}
ex_astr file_suffix;
offset = uri.rfind(".");
if (offset > 0)
{
file_suffix = uri.substr(offset, uri.length());
}
ex_wstr2astr(g_env.m_site_path, temp);
ex_astr index_path = temp + uri;
ex_wstr2astr(g_env.m_site_path, temp);
ex_astr index_path = temp + uri;
FILE* file = ex_fopen(index_path.c_str(), "rb");
if (file)
{
unsigned long file_size = 0;
char* buf = 0;
size_t ret = 0;
FILE* file = ex_fopen(index_path.c_str(), "rb");
if (file)
{
unsigned long file_size = 0;
char* buf = 0;
size_t ret = 0;
fseek(file, 0, SEEK_END);
file_size = ftell(file);
buf = new char[file_size];
memset(buf, 0, file_size);
fseek(file, 0, SEEK_SET);
ret = fread(buf, 1, file_size, file);
fclose(file);
fseek(file, 0, SEEK_END);
file_size = ftell(file);
buf = new char[file_size];
memset(buf, 0, file_size);
fseek(file, 0, SEEK_SET);
ret = fread(buf, 1, file_size, file);
fclose(file);
ex_astr content_type = _this->get_content_type(file_suffix);
ex_astr content_type = _this->get_content_type(file_suffix);
mg_printf(nc, "HTTP/1.0 200 OK\r\nAccess-Control-Allow-Origin: *\r\nContent-Length: %ld\r\nContent-Type: %s\r\n\r\n", file_size, content_type.c_str());
mg_send(nc, buf, (int)file_size);
delete []buf;
nc->flags |= MG_F_SEND_AND_CLOSE;
return;
} else if (b_is_html) {
ex_wstr page = L"<html lang=\"zh_CN\"><html><head><title>404 Not Found</title></head><body bgcolor=\"white\"><center><h1>404 Not Found</h1></center><hr><center><p>Teleport Assistor configuration page not found.</p></center></body></html>";
ex_wstr2astr(page, ret_buf, EX_CODEPAGE_UTF8);
mg_printf(nc, "HTTP/1.0 200 OK\r\nAccess-Control-Allow-Origin: *\r\nContent-Length: %ld\r\nContent-Type: %s\r\n\r\n", file_size, content_type.c_str());
mg_send(nc, buf, (int)file_size);
delete[]buf;
nc->flags |= MG_F_SEND_AND_CLOSE;
return;
}
else if (b_is_html)
{
ex_wstr page = L"<html lang=\"zh_CN\"><html><head><title>404 Not Found</title></head><body bgcolor=\"white\"><center><h1>404 Not Found</h1></center><hr><center><p>Teleport Assistor configuration page not found.</p></center></body></html>";
ex_wstr2astr(page, ret_buf, EX_CODEPAGE_UTF8);
mg_printf(nc, "HTTP/1.0 404 File Not Found\r\nAccess-Control-Allow-Origin: *\r\nContent-Length: %ld\r\nContent-Type: text/html\r\n\r\n%s", ret_buf.length(), ret_buf.c_str());
nc->flags |= MG_F_SEND_AND_CLOSE;
return;
}
mg_printf(nc, "HTTP/1.0 404 File Not Found\r\nAccess-Control-Allow-Origin: *\r\nContent-Length: %ld\r\nContent-Type: text/html\r\n\r\n%s", ret_buf.length(), ret_buf.c_str());
nc->flags |= MG_F_SEND_AND_CLOSE;
return;
}
}
break;
default:
break;
}
}
break;
default: break;
}
}
int TsHttpRpc::_parse_request(struct http_message* req, ex_astr& func_cmd, ex_astr& func_args)
{
if (NULL == req)
return TPE_FAILED;
if (NULL == req)
return TPE_FAILED;
bool is_get = true;
if (req->method.len == 3 && 0 == memcmp(req->method.p, "GET", req->method.len))
is_get = true;
else if (req->method.len == 4 && 0 == memcmp(req->method.p, "POST", req->method.len))
is_get = false;
else
return TPE_HTTP_METHOD;
bool is_get = true;
if (req->method.len == 3 && 0 == memcmp(req->method.p, "GET", req->method.len))
is_get = true;
else if (req->method.len == 4 && 0 == memcmp(req->method.p, "POST", req->method.len))
is_get = false;
else
return TPE_HTTP_METHOD;
ex_astrs strs;
ex_astrs strs;
size_t pos_start = 1; // skip first charactor, it must be '/'
size_t pos_start = 1; // skip first charactor, it must be '/'
size_t i = 0;
for (i = pos_start; i < req->uri.len; ++i)
{
if (req->uri.p[i] == '/')
{
if (i - pos_start > 0)
{
ex_astr tmp_uri;
tmp_uri.assign(req->uri.p + pos_start, i - pos_start);
strs.push_back(tmp_uri);
}
pos_start = i + 1; // skip current split chactor.
}
}
if (pos_start < req->uri.len)
{
ex_astr tmp_uri;
tmp_uri.assign(req->uri.p + pos_start, req->uri.len - pos_start);
strs.push_back(tmp_uri);
}
size_t i = 0;
for (i = pos_start; i < req->uri.len; ++i)
{
if (req->uri.p[i] == '/')
{
if (i - pos_start > 0)
{
ex_astr tmp_uri;
tmp_uri.assign(req->uri.p + pos_start, i - pos_start);
strs.push_back(tmp_uri);
}
pos_start = i + 1; // skip current split chactor.
}
}
if (pos_start < req->uri.len)
{
ex_astr tmp_uri;
tmp_uri.assign(req->uri.p + pos_start, req->uri.len - pos_start);
strs.push_back(tmp_uri);
}
if (0 == strs.size() || strs[0] != "api")
return TPE_PARAM;
if (0 == strs.size() || strs[0] != "api")
return TPE_PARAM;
if (is_get)
{
if (2 == strs.size())
{
func_cmd = strs[1];
}
else if (3 == strs.size())
{
func_cmd = strs[1];
func_args = strs[2];
}
else
{
return TPE_PARAM;
}
}
else
{
if (2 == strs.size())
{
func_cmd = strs[1];
}
else
{
return TPE_PARAM;
}
if (is_get)
{
if (2 == strs.size())
{
func_cmd = strs[1];
}
else if (3 == strs.size())
{
func_cmd = strs[1];
func_args = strs[2];
}
else
{
return TPE_PARAM;
}
}
else
{
if (2 == strs.size())
{
func_cmd = strs[1];
}
else
{
return TPE_PARAM;
}
if (req->body.len > 0)
{
func_args.assign(req->body.p, req->body.len);
}
}
if (req->body.len > 0)
{
func_args.assign(req->body.p, req->body.len);
}
}
if (func_args.length() > 0)
{
// decode param with url-decode.
size_t len = func_args.length() * 2;
ex_chars sztmp;
sztmp.resize(len);
memset(&sztmp[0], 0, len);
if (-1 == ex_url_decode(func_args.c_str(), (int)func_args.length(), &sztmp[0], (int)len, 0))
return TPE_HTTP_URL_ENCODE;
if (func_args.length() > 0)
{
// decode param with url-decode.
size_t len = func_args.length() * 2;
ex_chars sztmp;
sztmp.resize(len);
memset(&sztmp[0], 0, len);
if (-1 == ex_url_decode(func_args.c_str(), (int)func_args.length(), &sztmp[0], (int)len, 0))
return TPE_HTTP_URL_ENCODE;
func_args = &sztmp[0];
}
func_args = &sztmp[0];
}
EXLOGV("[rpc] method=%s, json_param=%s\n", func_cmd.c_str(), func_args.c_str());
EXLOGV("[rpc] method=%s, json_param=%s\n", func_cmd.c_str(), func_args.c_str());
return TPE_OK;
return TPE_OK;
}
void TsHttpRpc::_process_js_request(const ex_astr& func_cmd, const ex_astr& func_args, ex_astr& buf)
{
if (func_cmd == "get_version")
{
_rpc_func_get_version(func_args, buf);
}
else if (func_cmd == "get_config")
{
_rpc_func_get_config(func_args, buf);
}
else if (func_cmd == "set_config")
{
_rpc_func_set_config(func_args, buf);
}
else if (func_cmd == "file_action")
{
_rpc_func_file_action(func_args, buf);
}
else
{
EXLOGE("[rpc] got unknown command: %s\n", func_cmd.c_str());
_create_json_ret(buf, TPE_UNKNOWN_CMD);
}
if (func_cmd == "get_version")
{
_rpc_func_get_version(func_args, buf);
}
else if (func_cmd == "get_config")
{
_rpc_func_get_config(func_args, buf);
}
else if (func_cmd == "set_config")
{
_rpc_func_set_config(func_args, buf);
}
else if (func_cmd == "file_action")
{
_rpc_func_file_action(func_args, buf);
}
else
{
EXLOGE("[rpc] got unknown command: %s\n", func_cmd.c_str());
_create_json_ret(buf, TPE_UNKNOWN_CMD);
}
}
void TsHttpRpc::_create_json_ret(ex_astr& buf, int errcode)
{
// return {"code":123}
// return {"code":123}
Json::Value jr_root;
jr_root["code"] = errcode;
Json::Value jr_root;
jr_root["code"] = errcode;
Json::StreamWriterBuilder jwb;
std::unique_ptr<Json::StreamWriter> jwriter(jwb.newStreamWriter());
ex_aoss os;
@ -341,31 +350,35 @@ void TsHttpRpc::_create_json_ret(ex_astr& buf, Json::Value& jr_root)
buf = os.str();
}
void TsHttpRpc::_rpc_func_get_config(const ex_astr& func_args, ex_astr& buf) {
Json::Value jr_root;
jr_root["code"] = 0;
jr_root["data"] = g_cfg.get_root();
_create_json_ret(buf, jr_root);
void TsHttpRpc::_rpc_func_get_config(const ex_astr& func_args, ex_astr& buf)
{
Json::Value jr_root;
jr_root["code"] = 0;
jr_root["data"] = g_cfg.get_root();
_create_json_ret(buf, jr_root);
}
void TsHttpRpc::_rpc_func_set_config(const ex_astr& func_args, ex_astr& buf) {
void TsHttpRpc::_rpc_func_set_config(const ex_astr& func_args, ex_astr& buf)
{
Json::CharReaderBuilder jcrb;
std::unique_ptr<Json::CharReader> const jreader(jcrb.newCharReader());
const char *str_json_begin = func_args.c_str();
const char* str_json_begin = func_args.c_str();
Json::Value jsRoot;
ex_astr err;
if (!jreader->parse(str_json_begin, str_json_begin + func_args.length(), &jsRoot, &err)) {
if (!jreader->parse(str_json_begin, str_json_begin + func_args.length(), &jsRoot, &err))
{
_create_json_ret(buf, TPE_JSON_FORMAT);
return;
}
if(!g_cfg.save(func_args))
_create_json_ret(buf, TPE_FAILED);
else
_create_json_ret(buf, TPE_OK);
if (!g_cfg.save(func_args))
_create_json_ret(buf, TPE_FAILED);
else
_create_json_ret(buf, TPE_OK);
}
void TsHttpRpc::_rpc_func_file_action(const ex_astr& func_args, ex_astr& buf) {
void TsHttpRpc::_rpc_func_file_action(const ex_astr& func_args, ex_astr& buf)
{
_create_json_ret(buf, TPE_FAILED);
#if 0
Json::Reader jreader;
@ -406,13 +419,14 @@ void TsHttpRpc::_rpc_func_file_action(const ex_astr& func_args, ex_astr& buf) {
#endif
}
void TsHttpRpc::_rpc_func_get_version(const ex_astr& func_args, ex_astr& buf) {
Json::Value root_ret;
ex_wstr w_version = TP_ASSIST_VER;
ex_astr version;
ex_wstr2astr(w_version, version, EX_CODEPAGE_UTF8);
root_ret["version"] = version;
root_ret["code"] = TPE_OK;
_create_json_ret(buf, root_ret);
return;
void TsHttpRpc::_rpc_func_get_version(const ex_astr& func_args, ex_astr& buf)
{
Json::Value root_ret;
ex_wstr w_version = TP_ASSIST_VER;
ex_astr version;
ex_wstr2astr(w_version, version, EX_CODEPAGE_UTF8);
root_ret["version"] = version;
root_ret["code"] = TPE_OK;
_create_json_ret(buf, root_ret);
return;
}

View File

@ -54,47 +54,54 @@ typedef std::map<ex_astr, ex_astr> content_type_map;
class TsHttpRpc : public ExThreadBase
{
public:
TsHttpRpc();
~TsHttpRpc();
TsHttpRpc();
~TsHttpRpc();
bool init();
int get_port() {return m_port;}
int get_port() { return m_port; }
ex_astr get_content_type(ex_astr file_suffix)
{
content_type_map::iterator it = m_content_type_map.find(file_suffix);
if (it != m_content_type_map.end())
{
return it->second;
}
else
{
return "application/octet-stream";
}
};
ex_astr get_content_type(ex_astr file_suffix)
{
content_type_map::iterator it = m_content_type_map.find(file_suffix);
if (it != m_content_type_map.end())
{
return it->second;
}
else
{
return "application/octet-stream";
}
};
protected:
void _thread_loop(void);
void _thread_loop(void);
bool _on_init();
private:
int _parse_request(struct http_message* req, ex_astr& func_cmd, ex_astr& func_args);
void _process_js_request(const ex_astr& func_cmd, const ex_astr& func_args, ex_astr& buf);
void _create_json_ret(ex_astr& buf, int errcode);
void _create_json_ret(ex_astr& buf, Json::Value& jr_root);
int _parse_request(struct http_message* req, ex_astr& func_cmd, ex_astr& func_args);
void _rpc_func_get_config(const ex_astr& func_args, ex_astr& buf);
void _rpc_func_set_config(const ex_astr& func_args, ex_astr& buf);
void _rpc_func_file_action(const ex_astr& func_args, ex_astr& buf);
void _rpc_func_get_version(const ex_astr& func_args, ex_astr& buf);
void _process_js_request(const ex_astr& func_cmd, const ex_astr& func_args, ex_astr& buf);
static void _mg_event_handler(struct mg_connection *nc, int ev, void *ev_data);
void _create_json_ret(ex_astr& buf, int errcode);
void _create_json_ret(ex_astr& buf, Json::Value& jr_root);
void _rpc_func_get_config(const ex_astr& func_args, ex_astr& buf);
void _rpc_func_set_config(const ex_astr& func_args, ex_astr& buf);
void _rpc_func_file_action(const ex_astr& func_args, ex_astr& buf);
void _rpc_func_get_version(const ex_astr& func_args, ex_astr& buf);
static void _mg_event_handler(struct mg_connection* nc, int ev, void* ev_data);
private:
content_type_map m_content_type_map;
struct mg_mgr m_mg_mgr;
content_type_map m_content_type_map;
struct mg_mgr m_mg_mgr;
int m_port;
};

View File

@ -60,7 +60,7 @@ void TsWsClient::url_scheme_handler(const std::string& url)
}
method.assign(url, pos_protocol + 3, pos_method - pos_protocol - 3);
if(method.empty())
if (method.empty())
{
EXLOGE("[ws] no method, what should I do now?\n");
return;
@ -109,11 +109,11 @@ void TsWsClient::url_scheme_handler(const std::string& url)
{
_process_register(param, js_root);
}
else if(method == "run")
else if (method == "run")
{
_process_run(param, js_root);
}
else if(method == "replay_rdp")
else if (method == "replay_rdp")
{
_process_replay_rdp(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);
}
@ -215,8 +215,8 @@ void TsWsClient::_register(const std::string& ws_url, uint32_t assist_id, const
//
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)
{
@ -253,57 +253,57 @@ void TsWsClient::_mg_event_handler(struct mg_connection* nc, int ev, void* ev_da
switch (ev)
{
case MG_EV_CONNECT:
case MG_EV_CONNECT:
{
int status = *((int*)ev_data);
if (status != 0)
{
int status = *((int*)ev_data);
if (status != 0)
{
EXLOGE("[ERROR] -- connect to ws server failed: %d\n", status);
}
break;
EXLOGE("[ERROR] -- connect to ws server failed: %d\n", status);
}
case MG_EV_WEBSOCKET_HANDSHAKE_DONE:
break;
}
case MG_EV_WEBSOCKET_HANDSHAKE_DONE:
{
auto* hm = (struct http_message*)ev_data;
if (hm->resp_code == 101)
{
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;
EXLOGV("-- ws server connected\n");
}
else
{
EXLOGE("[ERROR] -- connect to ws server failed, HTTP code: %d\n", hm->resp_code);
}
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())
{
mg_send_websocket_frame(nc, WEBSOCKET_OP_TEXT, buf.c_str(), buf.length());
}
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())
{
mg_send_websocket_frame(nc, WEBSOCKET_OP_TEXT, buf.c_str(), buf.length());
}
break;
}
break;
}
case MG_EV_CLOSE:
{
EXLOGV("-- ws server disconnected\n");
_this->m_need_stop = true;
break;
}
case MG_EV_CLOSE:
{
EXLOGV("-- ws server disconnected\n");
_this->m_need_stop = true;
break;
}
}
}
@ -408,19 +408,19 @@ void TsWsClient::_on_message(const std::string& message, std::string& buf)
{
_rpc_func_run_client(buf, msg_req, js_root);
}
else if(msg_req.method == "replay_rdp")
else if (msg_req.method == "replay_rdp")
{
_rpc_func_replay_rdp(buf, msg_req, js_root);
}
else if(msg_req.method == "get_config")
else if (msg_req.method == "get_config")
{
_rpc_func_get_config(buf, msg_req, js_root);
}
else if(msg_req.method == "set_config")
else if (msg_req.method == "set_config")
{
_rpc_func_set_config(buf, msg_req, js_root);
}
else if(msg_req.method == "select_file")
else if (msg_req.method == "select_file")
{
_rpc_func_select_file(buf, msg_req, js_root);
}
@ -434,7 +434,7 @@ void TsWsClient::_on_message(const std::string& message, std::string& buf)
void TsWsClient::_rpc_func_get_config(ex_astr& buf, AssistMessage& msg_req, Json::Value& js_root)
{
Json::Value& ret = g_cfg.get_root();
if(ret["os_type"].isNull())
if (ret["os_type"].isNull())
ret["os_type"] = "macos";
_create_response(buf, msg_req, TPE_OK, "", ret);
@ -488,7 +488,7 @@ void TsWsClient::_rpc_func_replay_rdp(ex_astr& buf, AssistMessage& msg_req, Json
if (!js_param["rid"].isNumeric()
|| !js_param["web"].isString()
|| !js_param["sid"].isString()
)
)
{
_create_response(buf, msg_req, TPE_PARAM);
return;
@ -509,7 +509,7 @@ void TsWsClient::_rpc_func_replay_rdp(ex_astr& buf, AssistMessage& msg_req, Json
ex_astr a_url_base = js_param["web"].asCString();
ex_astr a_sid = js_param["sid"].asCString();
char cmd_args[1024] = { 0 };
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);
@ -530,10 +530,11 @@ void TsWsClient::_rpc_func_replay_rdp(ex_astr& buf, AssistMessage& msg_req, Json
// for macOS, Create Process should be fork()/exec()...
int ret_code = TPE_OK;
pid_t processId;
if ((processId = fork()) == 0) {
if ((processId = fork()) == 0)
{
int i = 0;
char** _argv = (char**)calloc(s_argv.size()+1, sizeof(char*));
char** _argv = (char**)calloc(s_argv.size() + 1, sizeof(char*));
if (!_argv)
return;
@ -545,16 +546,22 @@ void TsWsClient::_rpc_func_replay_rdp(ex_astr& buf, AssistMessage& msg_req, Json
execv(exec_file.c_str(), _argv);
for(i = 0; i < s_argv.size(); ++i) {
if(_argv[i] != NULL) {
for (i = 0; i < s_argv.size(); ++i)
{
if (_argv[i] != NULL)
{
free(_argv[i]);
}
}
free(_argv);
} else if (processId < 0) {
}
else if (processId < 0)
{
ret_code = TPE_FAILED;
} else {
}
else
{
ret_code = TPE_OK;
}
@ -586,7 +593,7 @@ void TsWsClient::_rpc_func_run_client(ex_astr& buf, AssistMessage& msg_req, Json
|| !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;
@ -594,12 +601,15 @@ void TsWsClient::_rpc_func_run_client(ex_astr& buf, AssistMessage& msg_req, Json
const char* interactive_mode = "no";
bool is_interactive_mode = false;
if(!js_param["is_interactive"].isNull()) {
if(!js_param["is_interactive"].isBool()) {
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()) {
if (js_param["is_interactive"].asBool())
{
interactive_mode = "yes";
is_interactive_mode = true;
}
@ -694,17 +704,19 @@ void TsWsClient::_rpc_func_run_client(ex_astr& buf, AssistMessage& msg_req, Json
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());
size_t n_pwd_len = strtol(str_pwd_len.c_str(), NULL, 16);
n_pwd_len -= real_sid.length();
n_pwd_len -= 2;
char szPwd[256] = {0};
for (int i = 0; i < n_pwd_len; i++)
{
szPwd[i] = '*';
}
// 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());
// size_t n_pwd_len = strtol(str_pwd_len.c_str(), NULL, 16);
// n_pwd_len -= real_sid.length();
// n_pwd_len -= 2;
// char szPwd[256] = {0};
// for (int i = 0; i < n_pwd_len; i++)
// {
// szPwd[i] = '*';
// }
// ex_astr real_sid(sid);
//ex_astr2wstr(real_sid, w_sid);
@ -718,7 +730,7 @@ void TsWsClient::_rpc_func_run_client(ex_astr& buf, AssistMessage& msg_req, Json
s_exec = g_cfg.rdp.application;
s_arg = g_cfg.rdp.cmdline;
sid = "02" + real_sid;
// sid = "02" + real_sid;
// s_argv.push_back("/f");
s_argv.push_back("/sec:tls");
@ -729,7 +741,8 @@ void TsWsClient::_rpc_func_run_client(ex_astr& buf, AssistMessage& msg_req, Json
// Automatically accept certificate on first connect
s_argv.push_back("/cert-tofu");
ex_astr _tmp_pass = "/p:PLACEHOLDER";
// ex_astr _tmp_pass = "/p:PLACEHOLDER";
ex_astr _tmp_pass = "/p:******";
//_tmp_pass += szPwd;
s_argv.push_back(_tmp_pass);
@ -881,20 +894,25 @@ void TsWsClient::_rpc_func_run_client(ex_astr& buf, AssistMessage& msg_req, Json
ex_astr::size_type p2 = 0;
ex_astr tmp;
for(;;){
for (;;)
{
p1 = s_arg.find("{password:");
if(p1 != ex_astr::npos) {
p2 = s_arg.find('}', p1+10);
if(p2 == ex_astr::npos) {
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) {
if (is_interactive_mode)
{
// 如果需要用户自己输入密码,则客户端命令行就不能带密码字段,需要抹去这个参数
s_arg.erase(p1, p2-p1+1);
s_arg.erase(p1, p2 - p1 + 1);
}
else{
else
{
s_arg.erase(p2, 1);
s_arg.erase(p1, 10);
}
@ -905,20 +923,25 @@ void TsWsClient::_rpc_func_run_client(ex_astr& buf, AssistMessage& msg_req, Json
}
}
for(;;){
for (;;)
{
p1 = s_arg.find("{interactive:");
if(p1 != ex_astr::npos) {
p2 = s_arg.find('}', p1+13);
if(p2 == ex_astr::npos) {
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) {
if (!is_interactive_mode)
{
// 如果无需用户自己输入密码,则需要抹去这个参数
s_arg.erase(p1, p2-p1+1);
s_arg.erase(p1, p2 - p1 + 1);
}
else{
else
{
s_arg.erase(p2, 1);
s_arg.erase(p1, 13);
}

View File

@ -34,6 +34,7 @@ public:
~TsWsClient();
void init();
void stop_all_client();
void url_scheme_handler(const std::string& url);
@ -71,6 +72,7 @@ private:
void _process_register(const std::string& param, Json::Value& js_root);
void _process_run(const std::string& param, Json::Value& js_root);
void _process_replay_rdp(const std::string& param, Json::Value& js_root);
private:

View File

@ -161,9 +161,9 @@ bool TsSessionManager::request_session(ex_astr& sid, TS_CONNECT_INFO* info)
if (info->protocol_type == TP_PROTOCOL_TYPE_RDP)
{
info->ref_count = 1; // 因为RDP连接之前可能会有很长时间用于确认是否连接、是否信任证书所以很容易超时我们认为将引用计数+1防止因超时被清除。
char szTmp[8] = {0};
snprintf(szTmp, 8, "%02X", (unsigned char)(info->acc_username.length() + info->acc_secret.length()));
sid += szTmp;
// char szTmp[8] = {0};
// snprintf(szTmp, 8, "%02X", (unsigned char)(info->acc_username.length() + info->acc_secret.length()));
// sid += szTmp;
}
return true;

View File

@ -518,11 +518,9 @@ $app.connect_remote = function (uni_id, acc_id, host_id, protocol_type, protocol
is_interactive: false,
};
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
});
args.rdp_width = $app.dlg_rdp_options.rdp_w;
args.rdp_height = $app.dlg_rdp_options.rdp_h;
args.rdp_console = $app.dlg_rdp_options.rdp_console;
}
if (uni_id === 'none')