mirror of https://github.com/tp4a/teleport
macOS: 支持SecureCRT做SSH客户端,SecureFX做SFTP客户端了。
macOS: 使用Terminal和iTerm2做SSH客户端时,无需用户敲一次回车键了。pull/130/head
parent
a883f8a80b
commit
0ddea7fabd
|
@ -1,27 +1,27 @@
|
|||
{
|
||||
"file_version": 3,
|
||||
"ssh": {
|
||||
"selected": "terminal",
|
||||
"available": [
|
||||
{
|
||||
"name":"terminal",
|
||||
"display": "终端(系统自带)",
|
||||
"app": "Terminal.app",
|
||||
"cmdline": "Basic",
|
||||
"ssh": {
|
||||
"selected": "terminal",
|
||||
"available": [
|
||||
{
|
||||
"name":"terminal",
|
||||
"display": "终端(系统自带)",
|
||||
"app": "Terminal.app",
|
||||
"cmdline": "Basic",
|
||||
"desc": []
|
||||
},
|
||||
{
|
||||
"name": "iterm2",
|
||||
"display": "iTerm2",
|
||||
"app": "iTerm2.app",
|
||||
},
|
||||
{
|
||||
"name": "iterm2",
|
||||
"display": "iTerm2",
|
||||
"app": "iTerm2.app",
|
||||
"cmdline": "Default",
|
||||
"desc": []
|
||||
},
|
||||
},
|
||||
{
|
||||
"name": "securecrt",
|
||||
"display": "SecureCRT",
|
||||
"app": "SecureCRT.app",
|
||||
"cmdline": "/T /N \"TP#ssh://{real_ip}\" /SSH2 /P {host_port} /PASSWORD **** {user_name}@{host_ip}",
|
||||
"app": "/Applications/SecureCRT.app/Contents/MacOS/SecureCRT",
|
||||
"cmdline": "/T /N \"TP#ssh://{real_ip}\" /SSH2 /L {user_name} /PASSWORD **** {host_ip}:{host_port}",
|
||||
"desc": []
|
||||
},
|
||||
{
|
||||
|
@ -31,8 +31,8 @@
|
|||
"cmdline": "",
|
||||
"desc": []
|
||||
}
|
||||
]
|
||||
},
|
||||
]
|
||||
},
|
||||
|
||||
"sftp": {
|
||||
"selected": "securefx",
|
||||
|
@ -40,8 +40,8 @@
|
|||
{
|
||||
"name": "securefx",
|
||||
"display": "SecureFX",
|
||||
"app": "SecureCRT.app",
|
||||
"cmdline": "/T /N \"TP#ssh://{real_ip}\" /SSH2 /P {host_port} /PASSWORD **** {user_name}@{host_ip}",
|
||||
"app": "/Applications/SecureFX.app/Contents/MacOS/SecureFX",
|
||||
"cmdline": "sftp://{user_name}:****@{host_ip}:{host_port}",
|
||||
"desc": []
|
||||
},
|
||||
{
|
||||
|
@ -89,18 +89,18 @@
|
|||
},
|
||||
|
||||
"rdp": {
|
||||
"selected": "freerdp",
|
||||
"available": [
|
||||
{
|
||||
"name": "FreeRDP",
|
||||
"display": "FreeRDP",
|
||||
"app": "",
|
||||
"selected": "freerdp",
|
||||
"available": [
|
||||
{
|
||||
"name": "FreeRDP",
|
||||
"display": "FreeRDP",
|
||||
"app": "",
|
||||
"cmdline": "",
|
||||
"desc": [
|
||||
"建议使用homebrew安装freerdp,安装后freerdp默认路径在:/usr/local/Cellar/freerdp/x.y.z/bin/xfreerdp",
|
||||
"首次安装freerdp后需要重新启动计算机"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,7 +29,7 @@ on CommandRun(theCmd, theProfile, theTitle)
|
|||
set profile to theProfile
|
||||
write text theCmd
|
||||
delay 0.5
|
||||
write text "useless"
|
||||
write text ""
|
||||
end tell
|
||||
end tell
|
||||
end tell
|
||||
|
@ -50,7 +50,7 @@ on CommandRun(theCmd, theProfile, theTitle)
|
|||
set name to theTitle
|
||||
write text theCmd
|
||||
delay 0.5
|
||||
write text "useless"
|
||||
write text ""
|
||||
end tell
|
||||
end tell
|
||||
end tell
|
||||
|
@ -70,7 +70,7 @@ on CommandRun(theCmd, theProfile, theTitle)
|
|||
set name to theTitle
|
||||
write text theCmd
|
||||
delay 0.5
|
||||
write text "useless"
|
||||
write text ""
|
||||
end tell
|
||||
end tell
|
||||
end tell
|
||||
|
|
|
@ -2,7 +2,6 @@ on scriptRun(argsCmd, argsProfile, argsTitle)
|
|||
set theCmd to (argsCmd)
|
||||
set theProfile to (argsProfile)
|
||||
set theTitle to (argsTitle)
|
||||
set useless to "useless"
|
||||
CommandRun(theCmd, theProfile, theTitle)
|
||||
end scriptRun
|
||||
|
||||
|
|
|
@ -68,10 +68,11 @@
|
|||
<div class="form-group form-group-sm">
|
||||
<label for="ssh-app" class="col-sm-2 control-label"><strong>程序路径:</strong></label>
|
||||
<div class="col-sm-9">
|
||||
<div class="input-group">
|
||||
<input id="ssh-app" type="text" class="form-control input-args" placeholder="客户端可执行程序文件路径" readonly="readonly">
|
||||
<span class="input-group-btn"><button class="btn btn-sm btn-primary" type="button" id="ssh-select-app">选择...</button></span>
|
||||
</div>
|
||||
<input id="ssh-app" type="text" class="form-control input-args" placeholder="客户端可执行程序文件路径">
|
||||
<!-- <div class="input-group">-->
|
||||
<!-- <input id="ssh-app" type="text" class="form-control input-args" placeholder="客户端可执行程序文件路径">-->
|
||||
<!-- <span class="input-group-btn"><button class="btn btn-sm btn-primary" type="button" id="ssh-select-app">选择...</button></span>-->
|
||||
<!-- </div>-->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@ -222,4 +223,4 @@
|
|||
|
||||
</body>
|
||||
|
||||
</html>
|
||||
</html>
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#define wrap_c_objc_h
|
||||
|
||||
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_select_app (void *_self);
|
||||
|
||||
// for cpp global object initialize.
|
||||
int cpp_main(void* _self, const char* cfg_file, const char* res_path);
|
||||
|
|
|
@ -16,5 +16,6 @@
|
|||
}
|
||||
|
||||
- (int) start_ssh_client:(NSString*)cmd_line termType:(NSString*)term_type termTheme:(NSString*)term_theme termTitle:(NSString*)term_title;
|
||||
- (int) select_app:(NSString*)ignore;
|
||||
|
||||
@end
|
||||
|
|
|
@ -37,6 +37,11 @@ int AppDelegate_start_ssh_client (void *_self, const char* cmd_line, const char*
|
|||
return [(__bridge id)_self start_ssh_client:cmdLine termType:termType termTheme:termTheme termTitle:termTitle];
|
||||
}
|
||||
|
||||
int AppDelegate_select_app (void *_self) {
|
||||
NSString* strIgnore = @"";
|
||||
return [(__bridge id)_self select_app:strIgnore];
|
||||
}
|
||||
|
||||
- (void) awakeFromNib {
|
||||
|
||||
// The path for the configuration file (by default: ~/.tp_assist.ini)
|
||||
|
@ -173,6 +178,27 @@ int AppDelegate_start_ssh_client (void *_self, const char* cmd_line, const char*
|
|||
}
|
||||
}
|
||||
|
||||
- (int) select_app:(NSString*)strIgnore {
|
||||
// NOT WORK
|
||||
// this function called by ts_http_rpc.c but it run in worker thread.
|
||||
// once we call select_app from worker thread, the NSOpenPanel alloc crash.
|
||||
// so we have had to show UI like "post a event and call callback" stuff.
|
||||
|
||||
NSOpenPanel *mySelectPanel = [[NSOpenPanel alloc] init];
|
||||
[mySelectPanel setCanChooseDirectories:YES];
|
||||
[mySelectPanel setCanChooseFiles:YES];
|
||||
[mySelectPanel setCanCreateDirectories:YES];
|
||||
[mySelectPanel setAllowsMultipleSelection:NO];
|
||||
[mySelectPanel setResolvesAliases:YES];
|
||||
|
||||
if([mySelectPanel runModal] == NSOKButton) {
|
||||
NSURL *ret = [mySelectPanel URL];
|
||||
NSLog(@"%@", ret.absoluteString);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
- (IBAction)visitWebsite:(id)sender {
|
||||
|
||||
NSURL *url = [NSURL URLWithString:@"https://www.tp4a.com/"];
|
||||
|
|
|
@ -115,10 +115,10 @@ bool TsCfg::_parse_app(const Json::Value& m_root, const ex_astr& str_app, APP_CO
|
|||
break;
|
||||
}
|
||||
|
||||
if (cfg.application.empty() || cfg.cmdline.empty()) {
|
||||
EXLOGE("invalid config, error 6.\n");
|
||||
return false;
|
||||
}
|
||||
// if (cfg.application.empty() || cfg.cmdline.empty()) {
|
||||
// EXLOGE("invalid config, error 6.\n");
|
||||
// return false;
|
||||
// }
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -137,6 +137,12 @@ bool TsCfg::_load(const ex_astr& str_json) {
|
|||
//===================================
|
||||
if(!_parse_app(m_root, "ssh", ssh))
|
||||
return false;
|
||||
if(!_parse_app(m_root, "sftp", sftp))
|
||||
return false;
|
||||
if(!_parse_app(m_root, "telnet", telnet))
|
||||
return false;
|
||||
if(!_parse_app(m_root, "rdp", rdp))
|
||||
return false;
|
||||
|
||||
#if 0
|
||||
if (!m_root["ssh"].isObject()) {
|
||||
|
|
|
@ -457,11 +457,15 @@ void TsHttpRpc::_rpc_func_run_client(const ex_astr& func_args, ex_astr& buf)
|
|||
|
||||
ex_astr teleport_ip = jsRoot["teleport_ip"].asCString();
|
||||
int teleport_port = jsRoot["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 = jsRoot["remote_host_ip"].asCString();
|
||||
ex_astr sid = jsRoot["session_id"].asCString();
|
||||
|
||||
ex_astr s_exec;
|
||||
ex_astr s_arg;
|
||||
ex_astrs s_argv;
|
||||
|
||||
|
||||
|
@ -602,13 +606,34 @@ void TsHttpRpc::_rpc_func_run_client(const ex_astr& func_args, ex_astr& buf)
|
|||
return;
|
||||
}
|
||||
|
||||
if(g_cfg.ssh.application.length() == 0) {
|
||||
_create_json_ret(buf, 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;
|
||||
}
|
||||
// _create_json_ret(buf, TPE_NOT_IMPLEMENT);
|
||||
// return;
|
||||
|
||||
if(g_cfg.sftp.application.length() == 0) {
|
||||
_create_json_ret(buf, TPE_NOT_EXISTS);
|
||||
return;
|
||||
}
|
||||
|
||||
s_exec = g_cfg.sftp.application;
|
||||
s_argv.push_back(s_exec.c_str());
|
||||
|
||||
s_arg = g_cfg.sftp.cmdline;
|
||||
|
||||
}
|
||||
}
|
||||
else if (pro_type == TP_PROTOCOL_TYPE_TELNET)
|
||||
{
|
||||
|
@ -621,70 +646,67 @@ void TsHttpRpc::_rpc_func_run_client(const ex_astr& func_args, ex_astr& buf)
|
|||
return;
|
||||
}
|
||||
|
||||
// ex_replace_all(w_exe_path, _T("{host_port}"), w_port);
|
||||
// ex_replace_all(w_exe_path, _T("{host_ip}"), w_teleport_ip.c_str());
|
||||
// ex_replace_all(w_exe_path, _T("{user_name}"), w_sid.c_str());
|
||||
// ex_replace_all(w_exe_path, _T("{real_ip}"), w_real_host_ip.c_str());
|
||||
//ex_replace_all(w_exe_path, _T("{assist_tools_path}"), g_env.m_tools_path.c_str());
|
||||
|
||||
//---- 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;
|
||||
for(;;) {
|
||||
ex_remove_white_space(tmp, EX_RSC_BEGIN);
|
||||
if(tmp.empty()) {
|
||||
break;
|
||||
}
|
||||
|
||||
if(tmp[0] == '"') {
|
||||
p1 = 1;
|
||||
p2 = tmp.find('"', p1);
|
||||
|
||||
if(p2 == ex_astr::npos) {
|
||||
_create_json_ret(buf, 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 root_ret;
|
||||
ex_astr utf8_path = s_exec;
|
||||
//ex_wstr2astr(w_exe_path, utf8_path, EX_CODEPAGE_UTF8);
|
||||
|
||||
ex_astrs::iterator it = s_argv.begin();
|
||||
for(; it != s_argv.end(); ++it) {
|
||||
utf8_path += " ";
|
||||
utf8_path += (*it);
|
||||
}
|
||||
ex_replace_all((*it), "{host_port}", str_teleport_port);
|
||||
ex_replace_all((*it), "{host_ip}", teleport_ip);
|
||||
ex_replace_all((*it), "{user_name}", sid);
|
||||
ex_replace_all((*it), "{real_ip}", real_host_ip);
|
||||
//ex_replace_all(utf8_path, _T("{assist_tools_path}"), g_env.m_tools_path.c_str());
|
||||
|
||||
utf8_path += " ";
|
||||
utf8_path += (*it);
|
||||
}
|
||||
|
||||
root_ret["path"] = utf8_path;
|
||||
|
||||
// if (!CreateProcess(NULL, (wchar_t *)w_exe_path.c_str(), NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi))
|
||||
// {
|
||||
// EXLOGE(_T("CreateProcess() failed. Error=0x%08X.\n %s\n"), GetLastError(), w_exe_path.c_str());
|
||||
// root_ret["code"] = TPE_START_CLIENT;
|
||||
// _create_json_ret(buf, root_ret);
|
||||
// return;
|
||||
// }
|
||||
|
||||
//system(utf8_path.c_str());
|
||||
//ex_astr __sid;
|
||||
//ex_wstr2astr(w_sid, __sid);
|
||||
//execlp("xfreerdp", "-u", __sid.c_str(), "-g", "800x600", "127.0.0.1:52089", NULL);
|
||||
// FILE *f = popen(utf8_path.c_str(), "r");
|
||||
// if(f == NULL) {
|
||||
// root_ret["code"] = TPE_FAILED;
|
||||
// } else {
|
||||
// root_ret["code"] = TPE_OK;
|
||||
// pclose(f);
|
||||
// }
|
||||
|
||||
// {
|
||||
// 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) {
|
||||
// free(_argv[i]);
|
||||
// }
|
||||
// }
|
||||
// free(_argv);
|
||||
//
|
||||
// }
|
||||
|
||||
|
||||
|
||||
// for macOS, Create Process should be fork()/exec()...
|
||||
pid_t processId;
|
||||
if ((processId = fork()) == 0) {
|
||||
|
@ -700,8 +722,8 @@ void TsHttpRpc::_rpc_func_run_client(const ex_astr& func_args, ex_astr& buf)
|
|||
}
|
||||
_argv[i] = NULL;
|
||||
|
||||
execv(s_exec.c_str(), _argv);
|
||||
|
||||
execv(s_exec.c_str(), _argv);
|
||||
|
||||
for(i = 0; i < s_argv.size(); ++i) {
|
||||
if(_argv[i] != NULL) {
|
||||
free(_argv[i]);
|
||||
|
@ -752,8 +774,44 @@ void TsHttpRpc::_rpc_func_set_config(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_NOT_IMPLEMENT);
|
||||
_create_json_ret(buf, TPE_FAILED);
|
||||
#if 0
|
||||
Json::Reader jreader;
|
||||
Json::Value jsRoot;
|
||||
|
||||
if (!jreader.parse(func_args.c_str(), jsRoot)) {
|
||||
_create_json_ret(buf, TPE_JSON_FORMAT);
|
||||
return;
|
||||
}
|
||||
|
||||
// if (!jsRoot["action"].isNumeric()) {
|
||||
// _create_json_ret(buf, TPE_PARAM);
|
||||
// return;
|
||||
// }
|
||||
// int action = jsRoot["action"].asUInt();
|
||||
|
||||
AppDelegate_select_app(g_app);
|
||||
_create_json_ret(buf, TPE_FAILED);
|
||||
|
||||
// if (ret) {
|
||||
// if (action == 1 || action == 2 || action == 3) {
|
||||
// ex_astr utf8_path;
|
||||
// ex_wstr2astr(wszReturnPath, utf8_path, EX_CODEPAGE_UTF8);
|
||||
// Json::Value root;
|
||||
// root["code"] = TPE_OK;
|
||||
// root["path"] = utf8_path;
|
||||
// _create_json_ret(buf, root);
|
||||
//
|
||||
// return;
|
||||
// } else {
|
||||
// _create_json_ret(buf, TPE_OK);
|
||||
// return;
|
||||
// }
|
||||
// } else {
|
||||
// _create_json_ret(buf, TPE_DATA);
|
||||
// return;
|
||||
// }
|
||||
#endif
|
||||
}
|
||||
|
||||
void TsHttpRpc::_rpc_func_get_version(const ex_astr& func_args, ex_astr& buf)
|
||||
|
|
|
@ -76,6 +76,7 @@
|
|||
7A27E4A61F6A899B004FDE5D /* ts_const.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ts_const.h; sourceTree = "<group>"; };
|
||||
7A27E4A71F6A8EEC004FDE5D /* ts_env.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ts_env.cpp; sourceTree = "<group>"; };
|
||||
7A27E4A81F6A8EEC004FDE5D /* ts_env.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ts_env.h; sourceTree = "<group>"; };
|
||||
7A2EC2C1219863A3009CFA85 /* tp_assist.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = tp_assist.entitlements; sourceTree = "<group>"; };
|
||||
7A40FFE21F7B2A4500F11697 /* AppDelegate-C-Interface.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "AppDelegate-C-Interface.h"; sourceTree = "<group>"; };
|
||||
7A7C6C8F21973C24006869D9 /* StatusIconAlt@3X.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "StatusIconAlt@3X.png"; sourceTree = "<group>"; };
|
||||
7A7C6C9021973C24006869D9 /* StatusIcon@3X.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "StatusIcon@3X.png"; sourceTree = "<group>"; };
|
||||
|
@ -250,6 +251,7 @@
|
|||
C149EBEE15D5214600B1F558 = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
7A2EC2C1219863A3009CFA85 /* tp_assist.entitlements */,
|
||||
7A1818951F8242E900F3C882 /* apple-scripts */,
|
||||
7AA2CD581F6AC0DA0074C92B /* site */,
|
||||
C149EBFC15D5214600B1F558 /* Frameworks */,
|
||||
|
@ -346,6 +348,15 @@
|
|||
attributes = {
|
||||
LastUpgradeCheck = 0930;
|
||||
ORGANIZATIONNAME = TP4A;
|
||||
TargetAttributes = {
|
||||
C149EBF815D5214600B1F558 = {
|
||||
SystemCapabilities = {
|
||||
com.apple.Sandbox = {
|
||||
enabled = 0;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
buildConfigurationList = C149EBF315D5214600B1F558 /* Build configuration list for PBXProject "tp_assist" */;
|
||||
compatibilityVersion = "Xcode 10.0";
|
||||
|
|
Loading…
Reference in New Issue