mirror of https://github.com/tp4a/teleport
Now core server not access database directly anymore.
TODO: tornado must use asynchronous handler otherwise core and web will lock each other.pull/32/merge
parent
b72ef8f8f9
commit
411eab32f0
|
@ -1,6 +1,8 @@
|
|||
# IDEA
|
||||
# 一些想法
|
||||
|
||||
简化core服务,使之不用直接访问数据库
|
||||
## 服务解耦
|
||||
|
||||
将core服务和web服务解耦合,让core服务不直接访问数据库。
|
||||
|
||||
优点:
|
||||
|
||||
|
@ -13,16 +15,61 @@
|
|||
|
||||
|
||||
|
||||
目前的core服务中直接访问数据库,涉及到:
|
||||
目前的core服务中直接访问数据库,涉及到
|
||||
|
||||
- 生成会话ID,需要根据认证ID获取认证信息,可改为web查询数据库,然后将认证信息传递给core服务。
|
||||
- 生成会话ID,需要根据认证ID获取认证信息;
|
||||
- 更新当前连接状态(连接、结束,出错等);
|
||||
|
||||
可改为web查询数据库,然后将数据传递给core服务。_但是这里有一个潜在的安全漏洞:认证信息中包含的私密信息会在网络上传播了。_解决的办法是:如果core和web在同一台主机上,没有漏洞,如果不在同一台主机上,core需要配置一个密钥放在配置文件中,web配置时需要输入此密钥才能与指定的core连接,且传输隐秘数据时使用此密钥进行加密。
|
||||
|
||||
|
||||
|
||||
|
||||
## 会话ID
|
||||
|
||||
关于会话ID的有效期,现有版本是设置一个引用计数,对于rdp可以使用两次,而ssh只能使用一次,原因是rdp连接时,通常第一次连接用于协商子协议,然后会断开,并立即重连并使用确定好的子协议进行后续操作。
|
||||
|
||||
改进的方法是:为一个会话ID设置一个标志及一个最后活动时间,会话ID刚生成时标志为false,调用take_session()时设置为true,当连接断开时(或者未能连接成功时)重置为false并更新最后活动时间为当前时间。标志为true时不允许重复take_session(),每次调用take_session()时检查标志为false的回话ID的最后活动时间,如果超过5秒未活动,则删除此会话ID。
|
||||
|
||||
这样做可以适配各种连接方式。
|
||||
这样做可以适配各种连接方式。
|
||||
|
||||
|
||||
|
||||
## 用户体验
|
||||
|
||||
纯净安装:基本上就是复制文件,没有别的操作了。安装完成后,提示teleport的运维管理WEB服务的URL,让用户进行访问。
|
||||
|
||||
### 纯净安装
|
||||
|
||||
**尽可能使用WEB-UI进行配置**
|
||||
|
||||
完全新安装的服务端,仅启动了web服务(但是web服务的监听IP和端口如何设定?监听IP可以设置为在0.0.0.0上监听,但是端口如何设定?)。因此,端口必须用配置文件的方式进行设定。其次,对于log级别、log输出路径等设定,涉及到系统的调试(可能web服务根本就启动不了,所以无法通过web界面进行设置),因此也需要通过配置文件的方式设定。
|
||||
|
||||
core与web之间通过JSON-RPC方式进行通讯,core并不直接操作数据库,而是转由web提供RPC接口进行操作。web服务并不直接读取core的配置,而是通过core提供的RPC接口获取或修改其配置。
|
||||
|
||||
core服务提供RPC接口,能够获取其内部状态,例如当前连接数、网络IO负载等等。
|
||||
|
||||
可以通过RPC接口停止或重启core和web服务。
|
||||
|
||||
web服务启动后,访问登录页面,但是如果缺少配置数据表,就跳转到配置页面。
|
||||
|
||||
- 设定所用数据库(可选本地sqlite,或者MySQL,如果是MySQL,需要给出root权限,或者指定有权限访问的数据库和用户名及密码,以及teleport相关表的前缀,默认为“tp_”),注意,这些信息必须存放在配置文件中,因此配置文件需要支持写入操作;
|
||||
- 创建配置数据库(包括用户表、配置表等);
|
||||
- 设定管理员密码(管理员用户名固定为admin);
|
||||
- 设置core服务的地址和端口(默认是本机127.0.0.1,端口包括RPC端口、SSH/RDP/Telnet端口等);
|
||||
- 设定core服务存放日志回放记录文件的目录地址;
|
||||
- core和web的配置信息均存放在.ini配置文件中,方便特定情况下用户手工编辑;
|
||||
|
||||
|
||||
安装时需要用户选择安装core还是web,还是二者皆安装。
|
||||
|
||||
安装完成后,core服务和web服务均会启动,在第一次启动时,需要创建config数据库,里面是一堆空表,只有用户表里面有一个管理员账号admin,安装部署人员可以使用此账号登陆系统。
|
||||
|
||||
需要增强服务的自检功能,例如端口已经被占用等,需要在日志中给出明确的错误信息。另外,考虑到将来core服务可能部署到多个主机上以提升承载能力,所以web需要访问core的数据时(包括取日志回放文件数据等),均使用RPC接口进行。
|
||||
|
||||
第一次登陆系统,会自动跳转到配置向导界面,让用户一步一步进行服务器配置。
|
||||
|
||||
|
||||
|
||||
-
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -79,13 +79,13 @@ public:
|
|||
//session 结束
|
||||
bool session_end(int id,int ret_code);
|
||||
//获取所有的认证ID
|
||||
bool get_auth_id_list_by_all(AuthInfo2Vec& auth_info_list);
|
||||
// bool get_auth_id_list_by_all(AuthInfo2Vec& auth_info_list);
|
||||
//通过IP获取认证ID
|
||||
bool get_auth_id_list_by_ip(ex_astr host_ip, AuthInfo2Vec& auth_info_list);
|
||||
// bool get_auth_id_list_by_ip(ex_astr host_ip, AuthInfo2Vec& auth_info_list);
|
||||
//获取所有的认证的信息
|
||||
bool get_auth_info_list_by_all(AuthInfo3Vec& auth_info_list);
|
||||
// bool get_auth_info_list_by_all(AuthInfo3Vec& auth_info_list);
|
||||
//通过IP获取认证信息
|
||||
bool get_auth_info_list_by_ip(ex_astr host_ip, AuthInfo3Vec& auth_info_list);
|
||||
// bool get_auth_info_list_by_ip(ex_astr host_ip, AuthInfo3Vec& auth_info_list);
|
||||
// //获取server 的配置信息
|
||||
// bool get_server_config(TS_DB_SERVER_CONFIG* server_config);
|
||||
//
|
||||
|
|
|
@ -1,50 +1,108 @@
|
|||
#include "ts_http_client.h"
|
||||
#include <mongoose.h>
|
||||
|
||||
#include<map>
|
||||
using namespace std;
|
||||
#include <ex/ex_str.h>
|
||||
|
||||
map<unsigned int, unsigned int> session_map;
|
||||
// #include<map>
|
||||
// using namespace std;
|
||||
//map<unsigned int, unsigned int> session_map;
|
||||
|
||||
int s_exit_flag = 0;
|
||||
void ts_url_encode(const char *src, ex_astr& out)
|
||||
{
|
||||
static const char *dont_escape = "._-$,;~()/";
|
||||
static const char *hex = "0123456789abcdef";
|
||||
|
||||
size_t s_len = strlen(src);
|
||||
size_t dst_len = s_len * 3 + 1;
|
||||
char* dst = new char[dst_len];
|
||||
memset(dst, 0, dst_len);
|
||||
|
||||
size_t i = 0, j = 0;
|
||||
|
||||
for (i = j = 0; dst_len > 0 && i < s_len && j + 2 < dst_len - 1; i++, j++) {
|
||||
if (isalnum(*(const unsigned char *)(src + i)) ||
|
||||
strchr(dont_escape, *(const unsigned char *)(src + i)) != NULL) {
|
||||
dst[j] = src[i];
|
||||
}
|
||||
else if (j + 3 < dst_len) {
|
||||
dst[j] = '%';
|
||||
dst[j + 1] = hex[(*(const unsigned char *)(src + i)) >> 4];
|
||||
dst[j + 2] = hex[(*(const unsigned char *)(src + i)) & 0xf];
|
||||
j += 2;
|
||||
}
|
||||
}
|
||||
|
||||
dst[j] = '\0';
|
||||
out = dst;
|
||||
delete []dst;
|
||||
}
|
||||
|
||||
typedef struct HTTP_DATA {
|
||||
bool exit_flag;
|
||||
bool have_error;
|
||||
ex_astr body;
|
||||
}HTTP_DATA;
|
||||
|
||||
//int s_exit_flag = 0;
|
||||
|
||||
static void ev_handler(struct mg_connection *nc, int ev, void *ev_data)
|
||||
{
|
||||
HTTP_DATA* hdata = (HTTP_DATA*)nc->user_data;
|
||||
struct http_message *hm = (struct http_message *) ev_data;
|
||||
|
||||
switch (ev) {
|
||||
case MG_EV_CONNECT:
|
||||
if (*(int *)ev_data != 0) {
|
||||
s_exit_flag = 1;
|
||||
hdata->exit_flag = true;
|
||||
hdata->have_error = true;
|
||||
}
|
||||
break;
|
||||
case MG_EV_HTTP_REPLY:
|
||||
nc->flags |= MG_F_CLOSE_IMMEDIATELY;
|
||||
s_exit_flag = 1;
|
||||
hdata->exit_flag = true;
|
||||
hdata->body.assign(hm->body.p, hm->body.len);
|
||||
break;
|
||||
case MG_EV_CLOSE:
|
||||
// if (s_exit_flag == 0) {
|
||||
// printf("Server closed connection\n");
|
||||
// s_exit_flag = 1;
|
||||
// }
|
||||
hdata->exit_flag = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool ts_http_get(ex_astr url)
|
||||
bool ts_http_get(const ex_astr& url, ex_astr& body)
|
||||
{
|
||||
struct mg_mgr mgr;
|
||||
mg_mgr_init(&mgr, NULL);
|
||||
|
||||
mg_connection* con = mg_connect_http(&mgr, ev_handler, url.c_str(), NULL, NULL);
|
||||
if (NULL == con)
|
||||
mg_connection* nc = mg_connect_http(&mgr, ev_handler, url.c_str(), NULL, NULL);
|
||||
if (NULL == nc)
|
||||
return false;
|
||||
|
||||
int count = 0;
|
||||
while (s_exit_flag == 0)
|
||||
HTTP_DATA* hdata = new HTTP_DATA;
|
||||
hdata->exit_flag = false;
|
||||
hdata->have_error = false;
|
||||
|
||||
nc->user_data = hdata;
|
||||
|
||||
// int count = 0;
|
||||
while (!hdata->exit_flag)
|
||||
{
|
||||
mg_mgr_poll(&mgr, 1000);
|
||||
count++;
|
||||
if (count > 2)
|
||||
break;
|
||||
mg_mgr_poll(&mgr, 100);
|
||||
// count++;
|
||||
// if (count > 2)
|
||||
// break;
|
||||
}
|
||||
|
||||
bool ret = !hdata->have_error;
|
||||
if (ret)
|
||||
body = hdata->body;
|
||||
|
||||
delete hdata;
|
||||
mg_mgr_free(&mgr);
|
||||
return true;
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
#include <ex.h>
|
||||
|
||||
bool ts_http_get(ex_astr url);
|
||||
void ts_url_encode(const char *src, ex_astr& out);
|
||||
bool ts_http_get(const ex_astr& url, ex_astr& body);
|
||||
|
||||
#endif // __TS_HTTP_CLIENT_H__
|
||||
|
|
|
@ -73,7 +73,6 @@ void TsHttpRpc::_set_stop_flag(void)
|
|||
m_stop_flag = true;
|
||||
}
|
||||
|
||||
|
||||
bool TsHttpRpc::init(void)
|
||||
{
|
||||
struct mg_connection* nc = NULL;
|
||||
|
@ -118,36 +117,43 @@ void TsHttpRpc::_mg_event_handler(struct mg_connection *nc, int ev, void *ev_dat
|
|||
{
|
||||
case MG_EV_HTTP_REQUEST:
|
||||
{
|
||||
#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";
|
||||
|
||||
ex_chars dbg_uri;
|
||||
dbg_uri.resize(hm->uri.len + 1);
|
||||
memset(&dbg_uri[0], 0, hm->uri.len + 1);
|
||||
memcpy(&dbg_uri[0], hm->uri.p, hm->uri.len);
|
||||
EXLOGV("[core-rpc] got %s request: %s\n", dbg_method, &dbg_uri[0]);
|
||||
#endif
|
||||
ex_astr ret_buf;
|
||||
|
||||
ex_astr method;
|
||||
ex_astr json_param;
|
||||
ex_rv rv = _this->_parse_request(hm, method, json_param);
|
||||
if (TSR_OK != rv)
|
||||
//const char* dbg_method = NULL;
|
||||
// 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);
|
||||
// ex_astr uri = &_uri[0];
|
||||
ex_astr uri;
|
||||
uri.assign(hm->uri.p, hm->uri.len);
|
||||
|
||||
EXLOGV("got request: %s\n", uri.c_str());
|
||||
|
||||
if (uri == "/rpc")
|
||||
{
|
||||
EXLOGE("[core-rpc] got invalid request.\n");
|
||||
_this->_create_json_ret(ret_buf, rv);
|
||||
ex_astr method;
|
||||
Json::Value json_param;
|
||||
|
||||
ex_rv rv = _this->_parse_request(hm, method, json_param);
|
||||
if (TSR_OK != rv)
|
||||
{
|
||||
EXLOGE("[core-rpc] got invalid request.\n");
|
||||
_this->_create_json_ret(ret_buf, rv);
|
||||
}
|
||||
else
|
||||
{
|
||||
_this->_process_request(method, json_param, ret_buf);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_this->_process_js_request(method, json_param, ret_buf);
|
||||
EXLOGE("[core-rpc] got invalid request: not `rpc` uri.\n");
|
||||
_this->_create_json_ret(ret_buf, TSR_INVALID_REQUEST, "not a `rpc` request.");
|
||||
}
|
||||
|
||||
|
||||
|
||||
mg_printf(nc, "HTTP/1.0 200 OK\r\nAccess-Control-Allow-Origin: *\r\nContent-Length: %d\r\nContent-Type: application/json\r\n\r\n%s", (int)ret_buf.size() - 1, &ret_buf[0]);
|
||||
nc->flags |= MG_F_SEND_AND_CLOSE;
|
||||
}
|
||||
|
@ -157,7 +163,7 @@ void TsHttpRpc::_mg_event_handler(struct mg_connection *nc, int ev, void *ev_dat
|
|||
}
|
||||
}
|
||||
|
||||
ex_rv TsHttpRpc::_parse_request(struct http_message* req, ex_astr& func_cmd, ex_astr& func_args)
|
||||
ex_rv TsHttpRpc::_parse_request(struct http_message* req, ex_astr& func_cmd, Json::Value& json_param)
|
||||
{
|
||||
if (NULL == req)
|
||||
return TSR_INVALID_REQUEST;
|
||||
|
@ -170,94 +176,59 @@ ex_rv TsHttpRpc::_parse_request(struct http_message* req, ex_astr& func_cmd, ex_
|
|||
else
|
||||
return TSR_INVALID_REQUEST;
|
||||
|
||||
std::vector<ex_astr> strs;
|
||||
ex_astr json_str;
|
||||
if (is_get)
|
||||
json_str.assign(req->query_string.p, req->query_string.len);
|
||||
else
|
||||
json_str.assign(req->body.p, req->body.len);
|
||||
|
||||
size_t pos_start = 1; // 跳过第一个字节,一定是 '/'
|
||||
|
||||
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; // 跳过当前找到的分隔符
|
||||
}
|
||||
}
|
||||
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())
|
||||
if (0 == json_str.length())
|
||||
return TSR_INVALID_REQUEST;
|
||||
|
||||
if (is_get)
|
||||
{
|
||||
if (1 == strs.size())
|
||||
{
|
||||
func_cmd = strs[0];
|
||||
}
|
||||
else if (2 == strs.size())
|
||||
{
|
||||
func_cmd = strs[0];
|
||||
func_args = strs[1];
|
||||
}
|
||||
else
|
||||
{
|
||||
return TSR_INVALID_REQUEST;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (1 == strs.size())
|
||||
{
|
||||
func_cmd = strs[0];
|
||||
}
|
||||
else
|
||||
{
|
||||
return TSR_INVALID_REQUEST;
|
||||
}
|
||||
// 将参数进行 url-decode 解码
|
||||
int len = json_str.length() * 2;
|
||||
ex_chars sztmp;
|
||||
sztmp.resize(len);
|
||||
memset(&sztmp[0], 0, len);
|
||||
if (-1 == ts_url_decode(json_str.c_str(), json_str.length(), &sztmp[0], len, 0))
|
||||
return TSR_INVALID_URL_ENCODE;
|
||||
|
||||
if (req->body.len > 0)
|
||||
{
|
||||
func_args.assign(req->body.p, req->body.len);
|
||||
}
|
||||
}
|
||||
json_str = &sztmp[0];
|
||||
|
||||
if (func_args.length()>0)
|
||||
{
|
||||
// 将参数进行 url-decode 解码
|
||||
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 TSR_INVALID_URL_ENCODE;
|
||||
|
||||
func_args = &sztmp[0];
|
||||
}
|
||||
|
||||
//EXLOGV("[rpc] method=%s, json_param=%s\n", func_cmd.c_str(), func_args.c_str());
|
||||
Json::Reader jreader;
|
||||
|
||||
if (!jreader.parse(json_str.c_str(), json_param))
|
||||
return TSR_INVALID_JSON_FORMAT;
|
||||
|
||||
if (json_param.isArray())
|
||||
return TSR_INVALID_JSON_PARAM;
|
||||
|
||||
if (json_param["method"].isNull() || !json_param["method"].isString())
|
||||
return TSR_INVALID_JSON_PARAM;
|
||||
|
||||
func_cmd = json_param["method"].asCString();
|
||||
json_param = json_param["param"];
|
||||
|
||||
return TSR_OK;
|
||||
}
|
||||
|
||||
void TsHttpRpc::_create_json_ret(ex_astr& buf, Json::Value& jr_root)
|
||||
void TsHttpRpc::_create_json_ret(ex_astr& buf, int errcode, const Json::Value& jr_data)
|
||||
{
|
||||
// 返回: {"code":errcode, "data":{jr_data}}
|
||||
|
||||
Json::FastWriter jr_writer;
|
||||
Json::Value jr_root;
|
||||
|
||||
jr_root["code"] = errcode;
|
||||
jr_root["data"] = jr_data;
|
||||
buf = jr_writer.write(jr_root);
|
||||
}
|
||||
|
||||
void TsHttpRpc::_create_json_ret(ex_astr& buf, int errcode)
|
||||
{
|
||||
// 返回: {"code":123}
|
||||
// 返回: {"code":errcode}
|
||||
|
||||
Json::FastWriter jr_writer;
|
||||
Json::Value jr_root;
|
||||
|
@ -266,27 +237,31 @@ void TsHttpRpc::_create_json_ret(ex_astr& buf, int errcode)
|
|||
buf = jr_writer.write(jr_root);
|
||||
}
|
||||
|
||||
void TsHttpRpc::_process_js_request(const ex_astr& func_cmd, const ex_astr& func_args, ex_astr& buf)
|
||||
void TsHttpRpc::_create_json_ret(ex_astr& buf, int errcode, const char* message)
|
||||
{
|
||||
// 返回: {"code":errcode, "message":message}
|
||||
|
||||
Json::FastWriter jr_writer;
|
||||
Json::Value jr_root;
|
||||
|
||||
jr_root["code"] = errcode;
|
||||
jr_root["message"] = message;
|
||||
buf = jr_writer.write(jr_root);
|
||||
}
|
||||
|
||||
void TsHttpRpc::_process_request(const ex_astr& func_cmd, const Json::Value& json_param, ex_astr& buf)
|
||||
{
|
||||
if (func_cmd == "request_session")
|
||||
{
|
||||
_rpc_func_request_session(func_args, buf);
|
||||
_rpc_func_request_session(json_param, buf);
|
||||
}
|
||||
else if (func_cmd == "enc")
|
||||
{
|
||||
_rpc_func_enc(func_args, buf);
|
||||
_rpc_func_enc(json_param, buf);
|
||||
}
|
||||
// else if (func_cmd == "get_auth_id")
|
||||
// {
|
||||
// _rpc_func_get_auth_id(func_args, buf);
|
||||
// }
|
||||
// else if (func_cmd == "get_auth_info")
|
||||
// {
|
||||
// _rpc_func_get_auth_info(func_args, buf);
|
||||
// }
|
||||
else if (func_cmd == "exit")
|
||||
{
|
||||
_rpc_func_exit(func_args, buf);
|
||||
_rpc_func_exit(json_param, buf);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -296,183 +271,211 @@ void TsHttpRpc::_process_js_request(const ex_astr& func_cmd, const ex_astr& func
|
|||
}
|
||||
|
||||
extern bool g_exit_flag; // 要求整个TS退出的标志(用于停止各个工作线程)
|
||||
void TsHttpRpc::_rpc_func_exit(const ex_astr& func_args, ex_astr& buf)
|
||||
void TsHttpRpc::_rpc_func_exit(const Json::Value& json_param, ex_astr& buf)
|
||||
{
|
||||
// 设置一个全局退出标志
|
||||
g_exit_flag = true;
|
||||
_create_json_ret(buf, TSR_OK);
|
||||
return;
|
||||
}
|
||||
|
||||
void TsHttpRpc::_rpc_func_request_session(const ex_astr& func_args, ex_astr& buf)
|
||||
void TsHttpRpc::_rpc_func_request_session(const Json::Value& json_param, ex_astr& buf)
|
||||
{
|
||||
// 申请一个会话ID
|
||||
// 入参: 两种模式
|
||||
// MODE A: 已知目标服务器信息及认证信息
|
||||
// 示例: {"ip":"192.168.5.11","port":22,"uname":"root","uauth":"abcdefg","authmode":1,"protocol":2,"enc":0}
|
||||
// ip: 目标服务器IP地址
|
||||
// port: 目标服务器端口
|
||||
// uname: 目标服务器认证所用的用户名
|
||||
// uauth: 目标服务器认证所用的密码或私钥
|
||||
// authmode: 1=password, 2=private-key
|
||||
// protocol: 1=rdp, 2=ssh
|
||||
// enc: 1=uauth中的内容是加密的,0=uauth中的内容是明文(仅用于开发测试阶段)
|
||||
// MODE B: 认证ID,需要根据这个ID到数据库中取得目标服务器信息及认证信息
|
||||
// 示例: {"authid":123456}
|
||||
// 返回:
|
||||
// SSH返回: {"code":0, "data":{"sid":"0123abcde"}}
|
||||
// RDP返回: {"code":0, "data":{"sid":"0123abcde0A"}}
|
||||
// 错误返回: {"code":1234}
|
||||
// https://github.com/eomsoft/teleport/wiki/TELEPORT-CORE-JSON-RPC#request_session
|
||||
|
||||
Json::Reader jreader;
|
||||
Json::Value jsRoot;
|
||||
int authid = 0;
|
||||
|
||||
if (!jreader.parse(func_args.c_str(), jsRoot))
|
||||
{
|
||||
_create_json_ret(buf, TSR_INVALID_JSON_FORMAT);
|
||||
return;
|
||||
}
|
||||
if (jsRoot.isArray())
|
||||
{
|
||||
_create_json_ret(buf, TSR_INVALID_JSON_PARAM);
|
||||
return;
|
||||
}
|
||||
|
||||
ex_astr host_ip;
|
||||
int host_port = 0;
|
||||
int sys_type = 0;
|
||||
ex_astr user_name;
|
||||
ex_astr user_auth;
|
||||
ex_astr user_param;
|
||||
|
||||
ex_astr account_name;
|
||||
int auth_mode = 0;
|
||||
int protocol = 0;
|
||||
int is_enc = 1;
|
||||
int auth_id = 0;
|
||||
// 入参模式
|
||||
if (!jsRoot["auth_id"].isNull())
|
||||
if (!json_param["authid"].isNull())
|
||||
{
|
||||
// 使用认证ID的方式申请SID
|
||||
if (!jsRoot["auth_id"].isNumeric())
|
||||
if (!json_param["authid"].isNumeric())
|
||||
{
|
||||
_create_json_ret(buf, TSR_INVALID_JSON_PARAM);
|
||||
return;
|
||||
}
|
||||
auth_id = jsRoot["auth_id"].asUInt();
|
||||
authid = json_param["authid"].asUInt();
|
||||
|
||||
|
||||
TS_DB_AUTH_INFO ts_auth_info;
|
||||
if (!g_db.get_auth_info(auth_id, ts_auth_info))
|
||||
if (!g_db.get_auth_info(authid, ts_auth_info))
|
||||
{
|
||||
_create_json_ret(buf, TSR_GETAUTH_INFO_ERROR);
|
||||
return;
|
||||
}
|
||||
if (ts_auth_info.host_lock !=0 )
|
||||
{
|
||||
_create_json_ret(buf, TSR_HOST_LOCK_ERROR);
|
||||
return;
|
||||
}
|
||||
if (ts_auth_info.account_lock != 0)
|
||||
{
|
||||
_create_json_ret(buf, TSR_ACCOUNT_LOCK_ERROR);
|
||||
return;
|
||||
}
|
||||
host_ip = ts_auth_info.host_ip;
|
||||
host_port = ts_auth_info.host_port;
|
||||
sys_type = ts_auth_info.sys_type;
|
||||
user_name = ts_auth_info.user_name;
|
||||
user_auth = ts_auth_info.user_auth;
|
||||
user_param = ts_auth_info.user_param;
|
||||
auth_mode = ts_auth_info.auth_mode;
|
||||
protocol = ts_auth_info.protocol;
|
||||
is_enc = ts_auth_info.is_encrypt;
|
||||
account_name = ts_auth_info.account_name;
|
||||
}
|
||||
else
|
||||
{
|
||||
// 判断参数是否正确
|
||||
if (jsRoot["ip"].isNull() || !jsRoot["ip"].isString()
|
||||
|| jsRoot["port"].isNull() || !jsRoot["port"].isNumeric()
|
||||
|| jsRoot["systype"].isNull() || !jsRoot["systype"].isNumeric()
|
||||
|| jsRoot["account"].isNull() || !jsRoot["account"].isString()
|
||||
|| jsRoot["uname"].isNull() || !jsRoot["uname"].isString()
|
||||
|| jsRoot["uauth"].isNull() || !jsRoot["uauth"].isString()
|
||||
|| jsRoot["authmode"].isNull() || !jsRoot["authmode"].isNumeric()
|
||||
|| jsRoot["protocol"].isNull() || !jsRoot["protocol"].isNumeric()
|
||||
|| jsRoot["enc"].isNull() || !jsRoot["enc"].isNumeric()
|
||||
)
|
||||
{
|
||||
_create_json_ret(buf, TSR_INVALID_JSON_PARAM);
|
||||
return;
|
||||
}
|
||||
|
||||
host_ip = jsRoot["ip"].asCString();
|
||||
host_port = jsRoot["port"].asUInt();
|
||||
sys_type = jsRoot["systype"].asUInt();
|
||||
account_name = jsRoot["account"].asCString();
|
||||
user_name = jsRoot["uname"].asCString();
|
||||
user_auth = jsRoot["uauth"].asCString();
|
||||
if (jsRoot["uparam"].isNull())
|
||||
{
|
||||
user_param = "";
|
||||
}
|
||||
else
|
||||
{
|
||||
user_param = jsRoot["uparam"].asCString();
|
||||
}
|
||||
|
||||
auth_mode = jsRoot["authmode"].asUInt();
|
||||
protocol = jsRoot["protocol"].asUInt();
|
||||
is_enc = jsRoot["enc"].asUInt();
|
||||
}
|
||||
|
||||
// 进一步判断参数是否合法
|
||||
if (host_ip.length() == 0 || host_port >= 65535 || account_name.length() == 0
|
||||
|| !(auth_mode == TS_AUTH_MODE_NONE || auth_mode == TS_AUTH_MODE_PASSWORD || auth_mode == TS_AUTH_MODE_PRIVATE_KEY)
|
||||
|| !(protocol == TS_PROXY_PROTOCOL_RDP || protocol == TS_PROXY_PROTOCOL_SSH || protocol == TS_PROXY_PROTOCOL_TELNET)
|
||||
|| !(is_enc == 0 || is_enc == 1)
|
||||
)
|
||||
{
|
||||
_create_json_ret(buf, TSR_INVALID_JSON_PARAM);
|
||||
return;
|
||||
}
|
||||
|
||||
if(is_enc)
|
||||
{
|
||||
if (user_auth.length() > 0)
|
||||
{
|
||||
ex_astr _auth;
|
||||
if (!ts_db_field_decrypt(user_auth, _auth))
|
||||
{
|
||||
_create_json_ret(buf, TSR_FAILED);
|
||||
return;
|
||||
}
|
||||
|
||||
user_auth = _auth;
|
||||
}
|
||||
}
|
||||
|
||||
// 生成一个session-id(内部会避免重复)
|
||||
ex_astr sid;
|
||||
ex_rv rv = g_session_mgr.request_session(sid, account_name, auth_id,
|
||||
host_ip, host_port, sys_type, protocol,
|
||||
user_name, user_auth, user_param, auth_mode);
|
||||
if (rv != TSR_OK)
|
||||
{
|
||||
_create_json_ret(buf, rv);
|
||||
return;
|
||||
}
|
||||
|
||||
EXLOGD("[core-rpc] new session-id: %s\n", sid.c_str());
|
||||
|
||||
Json::Value jr_root;
|
||||
jr_root["code"] = TSR_OK;
|
||||
jr_root["data"]["sid"] = sid;
|
||||
|
||||
_create_json_ret(buf, jr_root);
|
||||
_create_json_ret(buf, TSR_FAILED);
|
||||
}
|
||||
|
||||
void TsHttpRpc::_rpc_func_enc(const ex_astr& func_args, ex_astr& buf)
|
||||
// void TsHttpRpc::_rpc_func_request_session(const ex_astr& func_args, ex_astr& buf)
|
||||
// {
|
||||
// // 申请一个会话ID
|
||||
// // 入参: 两种模式
|
||||
// // MODE A: 已知目标服务器信息及认证信息
|
||||
// // 示例: {"ip":"192.168.5.11","port":22,"uname":"root","uauth":"abcdefg","authmode":1,"protocol":2,"enc":0}
|
||||
// // ip: 目标服务器IP地址
|
||||
// // port: 目标服务器端口
|
||||
// // uname: 目标服务器认证所用的用户名
|
||||
// // uauth: 目标服务器认证所用的密码或私钥
|
||||
// // authmode: 1=password, 2=private-key
|
||||
// // protocol: 1=rdp, 2=ssh
|
||||
// // enc: 1=uauth中的内容是加密的,0=uauth中的内容是明文(仅用于开发测试阶段)
|
||||
// // MODE B: 认证ID,需要根据这个ID到数据库中取得目标服务器信息及认证信息
|
||||
// // 示例: {"authid":123456}
|
||||
// // 返回:
|
||||
// // SSH返回: {"code":0, "data":{"sid":"0123abcde"}}
|
||||
// // RDP返回: {"code":0, "data":{"sid":"0123abcde0A"}}
|
||||
// // 错误返回: {"code":1234}
|
||||
//
|
||||
// Json::Reader jreader;
|
||||
// Json::Value jsRoot;
|
||||
//
|
||||
// if (!jreader.parse(func_args.c_str(), jsRoot))
|
||||
// {
|
||||
// _create_json_ret(buf, TSR_INVALID_JSON_FORMAT);
|
||||
// return;
|
||||
// }
|
||||
// if (jsRoot.isArray())
|
||||
// {
|
||||
// _create_json_ret(buf, TSR_INVALID_JSON_PARAM);
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// ex_astr host_ip;
|
||||
// int host_port = 0;
|
||||
// int sys_type = 0;
|
||||
// ex_astr user_name;
|
||||
// ex_astr user_auth;
|
||||
// ex_astr user_param;
|
||||
//
|
||||
// ex_astr account_name;
|
||||
// int auth_mode = 0;
|
||||
// int protocol = 0;
|
||||
// int is_enc = 1;
|
||||
// int auth_id = 0;
|
||||
// // 入参模式
|
||||
// if (!jsRoot["auth_id"].isNull())
|
||||
// {
|
||||
// // 使用认证ID的方式申请SID
|
||||
// if (!jsRoot["auth_id"].isNumeric())
|
||||
// {
|
||||
// _create_json_ret(buf, TSR_INVALID_JSON_PARAM);
|
||||
// return;
|
||||
// }
|
||||
// auth_id = jsRoot["auth_id"].asUInt();
|
||||
// TS_DB_AUTH_INFO ts_auth_info;
|
||||
// if (!g_db.get_auth_info(auth_id, ts_auth_info))
|
||||
// {
|
||||
// _create_json_ret(buf, TSR_GETAUTH_INFO_ERROR);
|
||||
// return;
|
||||
// }
|
||||
// if (ts_auth_info.host_lock !=0 )
|
||||
// {
|
||||
// _create_json_ret(buf, TSR_HOST_LOCK_ERROR);
|
||||
// return;
|
||||
// }
|
||||
// if (ts_auth_info.account_lock != 0)
|
||||
// {
|
||||
// _create_json_ret(buf, TSR_ACCOUNT_LOCK_ERROR);
|
||||
// return;
|
||||
// }
|
||||
// host_ip = ts_auth_info.host_ip;
|
||||
// host_port = ts_auth_info.host_port;
|
||||
// sys_type = ts_auth_info.sys_type;
|
||||
// user_name = ts_auth_info.user_name;
|
||||
// user_auth = ts_auth_info.user_auth;
|
||||
// user_param = ts_auth_info.user_param;
|
||||
// auth_mode = ts_auth_info.auth_mode;
|
||||
// protocol = ts_auth_info.protocol;
|
||||
// is_enc = ts_auth_info.is_encrypt;
|
||||
// account_name = ts_auth_info.account_name;
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// // 判断参数是否正确
|
||||
// if (jsRoot["ip"].isNull() || !jsRoot["ip"].isString()
|
||||
// || jsRoot["port"].isNull() || !jsRoot["port"].isNumeric()
|
||||
// || jsRoot["systype"].isNull() || !jsRoot["systype"].isNumeric()
|
||||
// || jsRoot["account"].isNull() || !jsRoot["account"].isString()
|
||||
// || jsRoot["uname"].isNull() || !jsRoot["uname"].isString()
|
||||
// || jsRoot["uauth"].isNull() || !jsRoot["uauth"].isString()
|
||||
// || jsRoot["authmode"].isNull() || !jsRoot["authmode"].isNumeric()
|
||||
// || jsRoot["protocol"].isNull() || !jsRoot["protocol"].isNumeric()
|
||||
// || jsRoot["enc"].isNull() || !jsRoot["enc"].isNumeric()
|
||||
// )
|
||||
// {
|
||||
// _create_json_ret(buf, TSR_INVALID_JSON_PARAM);
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// host_ip = jsRoot["ip"].asCString();
|
||||
// host_port = jsRoot["port"].asUInt();
|
||||
// sys_type = jsRoot["systype"].asUInt();
|
||||
// account_name = jsRoot["account"].asCString();
|
||||
// user_name = jsRoot["uname"].asCString();
|
||||
// user_auth = jsRoot["uauth"].asCString();
|
||||
// if (jsRoot["uparam"].isNull())
|
||||
// {
|
||||
// user_param = "";
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// user_param = jsRoot["uparam"].asCString();
|
||||
// }
|
||||
//
|
||||
// auth_mode = jsRoot["authmode"].asUInt();
|
||||
// protocol = jsRoot["protocol"].asUInt();
|
||||
// is_enc = jsRoot["enc"].asUInt();
|
||||
// }
|
||||
//
|
||||
// // 进一步判断参数是否合法
|
||||
// if (host_ip.length() == 0 || host_port >= 65535 || account_name.length() == 0
|
||||
// || !(auth_mode == TS_AUTH_MODE_NONE || auth_mode == TS_AUTH_MODE_PASSWORD || auth_mode == TS_AUTH_MODE_PRIVATE_KEY)
|
||||
// || !(protocol == TS_PROXY_PROTOCOL_RDP || protocol == TS_PROXY_PROTOCOL_SSH || protocol == TS_PROXY_PROTOCOL_TELNET)
|
||||
// || !(is_enc == 0 || is_enc == 1)
|
||||
// )
|
||||
// {
|
||||
// _create_json_ret(buf, TSR_INVALID_JSON_PARAM);
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// if(is_enc)
|
||||
// {
|
||||
// if (user_auth.length() > 0)
|
||||
// {
|
||||
// ex_astr _auth;
|
||||
// if (!ts_db_field_decrypt(user_auth, _auth))
|
||||
// {
|
||||
// _create_json_ret(buf, TSR_FAILED);
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// user_auth = _auth;
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// // 生成一个session-id(内部会避免重复)
|
||||
// ex_astr sid;
|
||||
// ex_rv rv = g_session_mgr.request_session(sid, account_name, auth_id,
|
||||
// host_ip, host_port, sys_type, protocol,
|
||||
// user_name, user_auth, user_param, auth_mode);
|
||||
// if (rv != TSR_OK)
|
||||
// {
|
||||
// _create_json_ret(buf, rv);
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// EXLOGD("[core-rpc] new session-id: %s\n", sid.c_str());
|
||||
//
|
||||
// Json::Value jr_root;
|
||||
// jr_root["code"] = TSR_OK;
|
||||
// jr_root["data"]["sid"] = sid;
|
||||
//
|
||||
// _create_json_ret(buf, jr_root);
|
||||
// }
|
||||
|
||||
void TsHttpRpc::_rpc_func_enc(const Json::Value& json_param, ex_astr& buf)
|
||||
{
|
||||
// https://github.com/eomsoft/teleport/wiki/TELEPORT-CORE-JSON-RPC#enc
|
||||
// 加密一个字符串 [ p=plain-text, c=cipher-text ]
|
||||
// 入参: {"p":"need be encrypt"}
|
||||
// 示例: {"p":"this-is-a-password"}
|
||||
|
@ -482,15 +485,7 @@ void TsHttpRpc::_rpc_func_enc(const ex_astr& func_args, ex_astr& buf)
|
|||
// 示例: {"code":0, "data":{"c":"Mxs340a9r3fs+3sdf=="}}
|
||||
// 错误返回: {"code":1234}
|
||||
|
||||
Json::Reader jreader;
|
||||
Json::Value jsRoot;
|
||||
|
||||
if (!jreader.parse(func_args.c_str(), jsRoot))
|
||||
{
|
||||
_create_json_ret(buf, TSR_INVALID_JSON_FORMAT);
|
||||
return;
|
||||
}
|
||||
if (jsRoot.isArray())
|
||||
if (json_param.isArray())
|
||||
{
|
||||
_create_json_ret(buf, TSR_INVALID_JSON_PARAM);
|
||||
return;
|
||||
|
@ -498,13 +493,13 @@ void TsHttpRpc::_rpc_func_enc(const ex_astr& func_args, ex_astr& buf)
|
|||
|
||||
ex_astr plain_text;
|
||||
|
||||
if (jsRoot["p"].isNull() || !jsRoot["p"].isString())
|
||||
if (json_param["p"].isNull() || !json_param["p"].isString())
|
||||
{
|
||||
_create_json_ret(buf, TSR_INVALID_JSON_PARAM);
|
||||
return;
|
||||
}
|
||||
|
||||
plain_text = jsRoot["p"].asCString();
|
||||
plain_text = json_param["p"].asCString();
|
||||
if (plain_text.length() == 0)
|
||||
{
|
||||
_create_json_ret(buf, TSR_DATA_LEN_ZERO);
|
||||
|
@ -518,11 +513,9 @@ void TsHttpRpc::_rpc_func_enc(const ex_astr& func_args, ex_astr& buf)
|
|||
return;
|
||||
}
|
||||
|
||||
Json::Value jr_root;
|
||||
jr_root["code"] = TSR_OK;
|
||||
jr_root["data"]["c"] = cipher_text;
|
||||
|
||||
_create_json_ret(buf, jr_root);
|
||||
Json::Value jr_data;
|
||||
jr_data["c"] = cipher_text;
|
||||
_create_json_ret(buf, TSR_OK, jr_data);
|
||||
}
|
||||
|
||||
#if 0
|
||||
|
|
|
@ -47,22 +47,20 @@ protected:
|
|||
void _set_stop_flag(void);
|
||||
|
||||
private:
|
||||
ex_rv _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);
|
||||
ex_rv _parse_request(struct http_message* req, ex_astr& func_cmd, Json::Value& json_param);
|
||||
void _process_request(const ex_astr& func_cmd, const Json::Value& json_param, ex_astr& buf);
|
||||
|
||||
void _create_json_ret(ex_astr& buf, Json::Value& jr_root);
|
||||
//void _create_json_ret(ex_astr& buf, Json::Value& jr_root);
|
||||
void _create_json_ret(ex_astr& buf, int errcode, const Json::Value& jr_root);
|
||||
void _create_json_ret(ex_astr& buf, int errcode);
|
||||
void _create_json_ret(ex_astr& buf, int errcode, const char* message);
|
||||
|
||||
// 请求一个会话ID
|
||||
void _rpc_func_request_session(const ex_astr& func_args, ex_astr& buf);
|
||||
void _rpc_func_request_session(const Json::Value& json_param, ex_astr& buf);
|
||||
// 加密一个字符串(返回的是密文的BASE64编码)
|
||||
void _rpc_func_enc(const ex_astr& func_args, ex_astr& buf);
|
||||
|
||||
// void _rpc_func_get_auth_id(const ex_astr& func_args, ex_astr& buf);
|
||||
// void _rpc_func_get_auth_info(const ex_astr& func_args, ex_astr& buf);
|
||||
|
||||
// ÒªÇóÕû¸öTSÍ˳ö
|
||||
void _rpc_func_exit(const ex_astr& func_args, ex_astr& buf);
|
||||
void _rpc_func_enc(const Json::Value& json_param, ex_astr& buf);
|
||||
// ÒªÇóÕû¸öºËÐÄ·þÎñÍ˳ö
|
||||
void _rpc_func_exit(const Json::Value& json_param, ex_astr& buf);
|
||||
|
||||
static void _mg_event_handler(struct mg_connection *nc, int ev, void *ev_data);
|
||||
|
||||
|
|
|
@ -1,18 +1,14 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
from .core import SwxCore
|
||||
from .core import WebServerCore
|
||||
from eom_common.eomcore.logger import *
|
||||
|
||||
__all__ = ['run']
|
||||
|
||||
|
||||
def run(options):
|
||||
log.initialize()
|
||||
# log.set_attribute(min_level=LOG_VERBOSE, log_datetime=False, trace_error=TRACE_ERROR_NONE)
|
||||
# log.set_attribute(min_level=LOG_VERBOSE, trace_error=TRACE_ERROR_NONE)
|
||||
# log.set_attribute(min_level=LOG_DEBUG, trace_error=TRACE_ERROR_FULL)
|
||||
|
||||
_app = SwxCore()
|
||||
_app = WebServerCore()
|
||||
if not _app.init(options):
|
||||
return 1
|
||||
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
import os
|
||||
# import sys
|
||||
import configparser
|
||||
|
||||
from eom_common.eomcore.logger import *
|
||||
|
@ -28,9 +27,6 @@ class AttrDict(dict):
|
|||
class ConfigFile(AttrDict):
|
||||
def __init__(self, **kwargs):
|
||||
super().__init__(**kwargs)
|
||||
# self.__file_name = None
|
||||
# self.__save_indent = 0
|
||||
# self.__loaded = False
|
||||
|
||||
def load_web(self, cfg_file):
|
||||
if not os.path.exists(cfg_file):
|
||||
|
@ -67,7 +63,7 @@ class ConfigFile(AttrDict):
|
|||
else:
|
||||
self['log_level'] = LOG_VERBOSE
|
||||
|
||||
log.set_attribute(min_level=self['log_level'])
|
||||
# log.set_attribute(min_level=self['log_level'])
|
||||
|
||||
return True
|
||||
|
||||
|
@ -112,31 +108,6 @@ class ConfigFile(AttrDict):
|
|||
self['core']['telnet']['enabled'] = _cfg['protocol-telnet'].getboolean('enabled', False)
|
||||
self['core']['telnet']['port'] = _cfg['protocol-telnet'].getint('bind-port', 52389)
|
||||
|
||||
|
||||
# if 'common' not in _cfg:
|
||||
# log.e('invalid configuration file: [{}]\n'.format(cfg_file))
|
||||
# return False
|
||||
#
|
||||
# _comm = _cfg['common']
|
||||
# self['server_port'] = _comm.getint('port', 7190)
|
||||
# self['log_file'] = _comm.get('log-file', None)
|
||||
# if self['log_file'] is not None:
|
||||
# self['log_path'] = os.path.dirname(self['log_file'])
|
||||
#
|
||||
# _level = _comm.getint('log-level', 2)
|
||||
# if _level == 0:
|
||||
# self['log_level'] = LOG_DEBUG
|
||||
# elif _level == 1:
|
||||
# self['log_level'] = LOG_VERBOSE
|
||||
# elif _level == 2:
|
||||
# self['log_level'] = LOG_INFO
|
||||
# elif _level == 3:
|
||||
# self['log_level'] = LOG_WARN
|
||||
# elif _level == 4:
|
||||
# self['log_level'] = LOG_ERROR
|
||||
# else:
|
||||
# self['log_level'] = LOG_VERBOSE
|
||||
|
||||
return True
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
APP_MODE_UNKNOWN = 0
|
||||
APP_MODE_NORMAL = 1
|
||||
APP_MODE_INSTALL = 2
|
||||
APP_MODE_UPGRADE = 3
|
||||
APP_MODE_MAINTENANCE = 4
|
|
@ -1,4 +1,5 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
|
@ -12,150 +13,63 @@ import tornado.web
|
|||
from eom_common.eomcore.eom_sqlite import get_sqlite_pool
|
||||
import eom_common.eomcore.utils as utils
|
||||
from eom_common.eomcore.logger import log
|
||||
from .const import *
|
||||
from .configs import app_cfg
|
||||
from .session import swx_session
|
||||
from .session import web_session
|
||||
|
||||
cfg = app_cfg()
|
||||
|
||||
|
||||
class SwxCore:
|
||||
class WebServerCore:
|
||||
def __init__(self):
|
||||
# self._cfg = ConfigFile()
|
||||
pass
|
||||
|
||||
def init(self, options):
|
||||
cfg.debug = False
|
||||
log.initialize()
|
||||
|
||||
cfg.dev_mode = options['dev_mode']
|
||||
cfg.app_path = os.path.abspath(options['app_path'])
|
||||
cfg.static_path = os.path.abspath(options['static_path'])
|
||||
cfg.data_path = os.path.abspath(options['data_path'])
|
||||
cfg.template_path = os.path.abspath(options['template_path'])
|
||||
cfg.res_path = os.path.abspath(options['res_path'])
|
||||
cfg.cfg_path = os.path.abspath(options['cfg_path'])
|
||||
|
||||
if not self._load_config(options):
|
||||
cfg.app_mode = APP_MODE_NORMAL
|
||||
# cfg.app_mode = APP_MODE_UNKNOWN
|
||||
# if os.path.exists(os.path.join(cfg.app_path, 'maintenance-mode')):
|
||||
# cfg.app_mode = APP_MODE_UPGRADE
|
||||
# else:
|
||||
# cfg.app_mode = APP_MODE_NORMAL
|
||||
|
||||
_cfg_file = os.path.join(cfg.cfg_path, 'web.ini')
|
||||
if not cfg.load_web(_cfg_file):
|
||||
return False
|
||||
|
||||
if cfg.log_file is None:
|
||||
if 'log_path' not in options:
|
||||
return False
|
||||
else:
|
||||
cfg.log_path = options['log_path']
|
||||
# TODO: 不要直接读取core.ini,而是通过core的json-rpc获取其配置数据
|
||||
_cfg_file = os.path.join(cfg.cfg_path, 'core.ini')
|
||||
if not cfg.load_core(_cfg_file):
|
||||
return False
|
||||
|
||||
cfg.log_file = os.path.join(cfg.log_path, 'tpweb.log')
|
||||
cfg.log_path = os.path.abspath(options['log_path'])
|
||||
cfg.log_file = os.path.join(cfg.log_path, 'tpweb.log')
|
||||
|
||||
if not os.path.exists(cfg.log_path):
|
||||
utils.make_dir(cfg.log_path)
|
||||
if not os.path.exists(cfg.log_path):
|
||||
log.e('Can not create log path.\n')
|
||||
log.e('Can not create log path:{}\n'.format(cfg.log_path))
|
||||
return False
|
||||
|
||||
log.set_attribute(filename=cfg.log_file)
|
||||
log.set_attribute(min_level=cfg.log_level, filename=cfg.log_file)
|
||||
# log.set_attribute(min_level=self['log_level'])
|
||||
|
||||
if 'app_path' not in options:
|
||||
return False
|
||||
else:
|
||||
cfg.app_path = options['app_path']
|
||||
|
||||
if 'static_path' in options:
|
||||
cfg.static_path = options['static_path']
|
||||
else:
|
||||
cfg.static_path = os.path.join(options['app_path'], 'static')
|
||||
|
||||
if 'data_path' in options:
|
||||
cfg.data_path = options['data_path']
|
||||
else:
|
||||
cfg.data_path = os.path.join(options['app_path'], 'data')
|
||||
|
||||
if 'template_path' in options:
|
||||
cfg.template_path = options['template_path']
|
||||
else:
|
||||
cfg.template_path = os.path.join(options['app_path'], 'view')
|
||||
|
||||
if 'res_path' in options:
|
||||
cfg.res_path = options['res_path']
|
||||
else:
|
||||
cfg.res_path = os.path.join(options['app_path'], 'res')
|
||||
|
||||
if not swx_session().init():
|
||||
if not web_session().init():
|
||||
return False
|
||||
|
||||
# TODO: 这里不要初始化数据库接口,需要根据配置文件来决定使用什么数据库(初始安装时还没有配置数据库信息)
|
||||
# get_mysql_pool().init(cfg.mysql_ip, cfg.mysql_port, cfg.mysql_user, cfg.mysql_pass)
|
||||
# db_path = os.path.join(cfg.data_path, 'ts_db.db')
|
||||
get_sqlite_pool().init(cfg.data_path)
|
||||
|
||||
# var_js = os.path.join(cfg.static_path, 'js', 'var.js')
|
||||
# try:
|
||||
# # if not os.path.exists(var_js):
|
||||
# f = open(var_js, 'w')
|
||||
# f.write("\"use strict\";\nvar teleport_ip = \"{}\";\n".format(get_sqlite_pool().get_config_server_ip()))
|
||||
# f.close()
|
||||
# except Exception:
|
||||
# log.e('can not load config: server_ip.\n')
|
||||
# return False
|
||||
|
||||
return True
|
||||
|
||||
def _load_config(self, options):
|
||||
if 'cfg_path' in options:
|
||||
_cfg_path = options['cfg_path']
|
||||
else:
|
||||
_cfg_path = os.path.join(options['app_path'], 'conf')
|
||||
|
||||
_cfg_file = os.path.join(_cfg_path, 'web.ini')
|
||||
if not cfg.load_web(_cfg_file):
|
||||
return False
|
||||
|
||||
_cfg_file = os.path.join(_cfg_path, 'core.ini')
|
||||
if not cfg.load_core(_cfg_file):
|
||||
return False
|
||||
|
||||
cfg.cfg_path = _cfg_path
|
||||
|
||||
return True
|
||||
|
||||
@staticmethod
|
||||
def _daemon():
|
||||
# fork for daemon.
|
||||
if sys.platform == 'win32':
|
||||
# log.v('os.fork() not support Windows, operation ignored.\n')
|
||||
return True
|
||||
|
||||
try:
|
||||
pid = os.fork()
|
||||
if pid > 0:
|
||||
# log.w('parent #1 exit.\n')
|
||||
# return False
|
||||
os._exit(0)
|
||||
except OSError:
|
||||
log.e('fork #1 failed.\n')
|
||||
os._exit(1)
|
||||
|
||||
# Detach from parent env.
|
||||
os.chdir('/')
|
||||
os.umask(0)
|
||||
os.setsid()
|
||||
|
||||
# Second fork.
|
||||
try:
|
||||
pid = os.fork()
|
||||
if pid > 0:
|
||||
# log.w('parent #2 exit.\n')
|
||||
# return False
|
||||
os._exit(0)
|
||||
except OSError:
|
||||
log.e('fork #2 failed.\n')
|
||||
# return False
|
||||
os._exit(1)
|
||||
|
||||
# OK I'm daemon now.
|
||||
for f in sys.stdout, sys.stderr:
|
||||
f.flush()
|
||||
si = open('/dev/null', 'r')
|
||||
so = open('/dev/null', 'a+')
|
||||
se = open('/dev/null', 'a+')
|
||||
os.dup2(si.fileno(), sys.stdin.fileno())
|
||||
os.dup2(so.fileno(), sys.stdout.fileno())
|
||||
os.dup2(se.fileno(), sys.stderr.fileno())
|
||||
|
||||
# test print() not raise exception.
|
||||
# print('good.')
|
||||
|
||||
return True
|
||||
|
||||
def run(self):
|
||||
|
@ -185,6 +99,7 @@ class SwxCore:
|
|||
'static_hash_cache': False,
|
||||
}
|
||||
|
||||
# TODO: 配置文件中应该增加 debug 选项
|
||||
# if cfg.debug:
|
||||
# settings['compiled_template_cache'] = False
|
||||
# settings['static_hash_cache'] = False
|
||||
|
@ -194,50 +109,6 @@ class SwxCore:
|
|||
from eom_app.controller import controllers
|
||||
web_app = tornado.web.Application(controllers, **settings)
|
||||
|
||||
# if sys.platform == 'win32':
|
||||
# web_app.listen(cfg.server_port)
|
||||
# log.v('Web Server start on http://127.0.0.1:{}\n'.format(cfg.server_port))
|
||||
# tornado.ioloop.IOLoop.instance().start()
|
||||
# else:
|
||||
# if not cfg.debug:
|
||||
# if not self._daemon():
|
||||
# return False
|
||||
# # 进入daemon模式了,不再允许输出信息到控制台了
|
||||
# log.set_attribute(console=False, filename='/var/log/eom/ts-backend.log')
|
||||
# log.v('\n=====================================\n')
|
||||
#
|
||||
# def _run(port):
|
||||
# log.v('Web Server start on http://127.0.0.1:{}\n'.format(port))
|
||||
# web_app.listen(port)
|
||||
# tornado.ioloop.IOLoop.instance().start()
|
||||
# log.w('a tornado io-loop exit.\n')
|
||||
#
|
||||
# jobs = list()
|
||||
# port = cfg.server_port
|
||||
# for x in range(cfg.server_worker):
|
||||
# p = multiprocessing.Process(target=_run, args=(port,))
|
||||
# jobs.append(p)
|
||||
# p.start()
|
||||
# port = port + 1
|
||||
#
|
||||
# else:
|
||||
# # sockets = tornado.netutil.bind_sockets(cfg.server_port)
|
||||
# # tornado.process.fork_processes(2)
|
||||
# # server = tornado.httpserver.HTTPServer(web_app)
|
||||
# # server.add_sockets(sockets)
|
||||
# web_app.listen(cfg.server_port)
|
||||
# log.v('Web Server start on http://127.0.0.1:{}\n'.format(cfg.server_port))
|
||||
# tornado.ioloop.IOLoop.instance().start()
|
||||
|
||||
# server = tornado.httpserver.HTTPServer(web_app, ssl_options={
|
||||
# 'certfile': os.path.join(cfg.cfg_path, 'ssl', 'server.pem'),
|
||||
# 'keyfile': os.path.join(cfg.cfg_path, 'ssl', 'server.key')
|
||||
# })
|
||||
# if sys.platform == 'win32':
|
||||
# log.set_attribute(console=False, filename='/var/log/eom_ts/ts-backend.log')
|
||||
# else:
|
||||
# log.set_attribute(console=False, filename='/var/log/eom_ts/ts-backend.log')
|
||||
|
||||
server = tornado.httpserver.HTTPServer(web_app)
|
||||
try:
|
||||
server.listen(cfg.server_port)
|
||||
|
@ -246,9 +117,5 @@ class SwxCore:
|
|||
log.e('Can not listen on port {}, maybe it been used by another application.\n'.format(cfg.server_port))
|
||||
return 0
|
||||
|
||||
# if not cfg.dev_mode:
|
||||
# log_file = os.path.join(cfg.log_path, 'tpweb.log')
|
||||
# log.set_attribute(console=False, filename=log_file)
|
||||
|
||||
tornado.ioloop.IOLoop.instance().start()
|
||||
return 0
|
||||
|
|
|
@ -9,19 +9,19 @@ cfg = app_cfg()
|
|||
|
||||
SESSION_EXPIRE = 3600 # 60*60
|
||||
|
||||
|
||||
# TODO: session接口需要支持超时(超时的session应该移除,避免内存占用越来越大)
|
||||
# SESSION_EXPIRE = 1800 # 30*60
|
||||
# SESSION_EXPIRE = 30
|
||||
|
||||
class SwxSession:
|
||||
class WebSession:
|
||||
"""
|
||||
:type _mem_client: pymemcache.client.base.Client
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
import builtins
|
||||
if '__swx_session__' in builtins.__dict__:
|
||||
raise RuntimeError('SwxSession object exists, you can not create more than one instance.')
|
||||
if '__web_session__' in builtins.__dict__:
|
||||
raise RuntimeError('WebSession object exists, you can not create more than one instance.')
|
||||
self._session_dict = dict()
|
||||
|
||||
def init(self):
|
||||
|
@ -41,14 +41,14 @@ class SwxSession:
|
|||
return v
|
||||
|
||||
|
||||
def swx_session():
|
||||
def web_session():
|
||||
"""
|
||||
取得 SwxSession 的唯一实例
|
||||
|
||||
:rtype : SwxSession
|
||||
:rtype : WebSession
|
||||
"""
|
||||
|
||||
import builtins
|
||||
if '__swx_session__' not in builtins.__dict__:
|
||||
builtins.__dict__['__swx_session__'] = SwxSession()
|
||||
return builtins.__dict__['__swx_session__']
|
||||
if '__web_session__' not in builtins.__dict__:
|
||||
builtins.__dict__['__web_session__'] = WebSession()
|
||||
return builtins.__dict__['__web_session__']
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
import os
|
||||
from . import rpc
|
||||
from . import auth
|
||||
from . import host
|
||||
from . import cert
|
||||
|
@ -10,6 +11,7 @@ from . import set
|
|||
from . import group
|
||||
from . import index
|
||||
from . import record
|
||||
from . import maintenance
|
||||
import tornado.web
|
||||
|
||||
from eom_app.app.configs import app_cfg
|
||||
|
@ -21,6 +23,13 @@ __all__ = ['controllers']
|
|||
controllers = [
|
||||
(r'/', index.IndexHandler),
|
||||
|
||||
# (r'/install/', maintenance.InstallHandler),
|
||||
# (r'/install', maintenance.InstallHandler),
|
||||
(r'/maintenance/', maintenance.IndexHandler),
|
||||
(r'/maintenance', maintenance.IndexHandler),
|
||||
|
||||
(r'/rpc', rpc.RpcHandler),
|
||||
|
||||
(r'/auth/login', auth.LoginHandler),
|
||||
(r'/auth/verify-user', auth.VerifyUser),
|
||||
(r'/auth/logout', auth.LogoutHandler),
|
||||
|
|
|
@ -6,11 +6,11 @@ from random import Random
|
|||
|
||||
from eom_app.module import user
|
||||
from eom_common.eomcore.logger import *
|
||||
from .base import SwxBaseHandler, SwxJsonpHandler, SwxAuthJsonHandler
|
||||
from .base import SwxAppHandler, SwxJsonpHandler, SwxAuthJsonHandler
|
||||
from .helper.captcha import gen_captcha
|
||||
|
||||
|
||||
class LoginHandler(SwxBaseHandler):
|
||||
class LoginHandler(SwxAppHandler):
|
||||
def get(self):
|
||||
ref = self.get_argument('ref', '/')
|
||||
|
||||
|
@ -71,7 +71,7 @@ class VerifyUser(SwxJsonpHandler):
|
|||
self.write_jsonp(-1)
|
||||
|
||||
|
||||
class LogoutHandler(SwxBaseHandler):
|
||||
class LogoutHandler(SwxAppHandler):
|
||||
def get(self):
|
||||
user = self.get_current_user()
|
||||
user['is_login'] = False
|
||||
|
@ -81,7 +81,7 @@ class LogoutHandler(SwxBaseHandler):
|
|||
self.redirect('/auth/login')
|
||||
|
||||
|
||||
class GetCaptchaHandler(SwxBaseHandler):
|
||||
class GetCaptchaHandler(SwxAppHandler):
|
||||
def get(self):
|
||||
code, img_data = gen_captcha()
|
||||
self.set_session('captcha', code)
|
||||
|
@ -266,11 +266,11 @@ class ModifyPwd(SwxAuthJsonHandler):
|
|||
# self.write_json(-1)
|
||||
|
||||
|
||||
def random_str(randomlength=8):
|
||||
_str = ''
|
||||
chars = 'AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz0123456789'
|
||||
length = len(chars) - 1
|
||||
_random = Random()
|
||||
for i in range(randomlength):
|
||||
_str += chars[_random.randint(0, length)]
|
||||
return _str
|
||||
# def random_str(randomlength=8):
|
||||
# _str = ''
|
||||
# chars = 'AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz0123456789'
|
||||
# length = len(chars) - 1
|
||||
# _random = Random()
|
||||
# for i in range(randomlength):
|
||||
# _str += chars[_random.randint(0, length)]
|
||||
# return _str
|
||||
|
|
|
@ -10,7 +10,11 @@ import mako.template
|
|||
import tornado.web
|
||||
from tornado.escape import json_encode
|
||||
|
||||
from eom_app.app.session import swx_session
|
||||
from eom_app.app.session import web_session
|
||||
from eom_app.app.configs import app_cfg
|
||||
from eom_app.app.const import *
|
||||
|
||||
cfg = app_cfg()
|
||||
|
||||
|
||||
class SwxBaseHandler(tornado.web.RequestHandler):
|
||||
|
@ -19,6 +23,7 @@ class SwxBaseHandler(tornado.web.RequestHandler):
|
|||
|
||||
self._s_id = None
|
||||
self._s_val = dict()
|
||||
# self.lookup = None
|
||||
|
||||
def initialize(self):
|
||||
template_path = self.get_template_path()
|
||||
|
@ -34,25 +39,26 @@ class SwxBaseHandler(tornado.web.RequestHandler):
|
|||
self.finish(self.render_string(template_path, **kwargs))
|
||||
|
||||
def prepare(self):
|
||||
super().prepare()
|
||||
|
||||
if self.application.settings.get("xsrf_cookies"):
|
||||
x = self.xsrf_token
|
||||
# if self.application.settings.get("xsrf_cookies"):
|
||||
# x = self.xsrf_token
|
||||
|
||||
self._s_id = self.get_cookie('_sid')
|
||||
if self._s_id is None:
|
||||
self._s_id = 'ywl_{}_{}'.format(int(time.time()), binascii.b2a_hex(os.urandom(8)).decode())
|
||||
self.set_cookie('_sid', self._s_id)
|
||||
swx_session().add(self._s_id, self._s_val)
|
||||
web_session().add(self._s_id, self._s_val)
|
||||
else:
|
||||
# print('sid:', self._s_id)
|
||||
self._s_val = swx_session().get(self._s_id)
|
||||
self._s_val = web_session().get(self._s_id)
|
||||
if self._s_val is None:
|
||||
self._s_val = dict()
|
||||
swx_session().add(self._s_id, self._s_val)
|
||||
web_session().add(self._s_id, self._s_val)
|
||||
|
||||
def set_session(self, name, value):
|
||||
self._s_val[name] = value
|
||||
swx_session().set(self._s_id, self._s_val)
|
||||
web_session().set(self._s_id, self._s_val)
|
||||
|
||||
def get_session(self, name, default=None):
|
||||
if name in self._s_val:
|
||||
|
@ -81,7 +87,23 @@ class SwxBaseHandler(tornado.web.RequestHandler):
|
|||
return user
|
||||
|
||||
|
||||
class SwxJsonpHandler(SwxBaseHandler):
|
||||
class SwxAppHandler(SwxBaseHandler):
|
||||
def __init__(self, application, request, **kwargs):
|
||||
super().__init__(application, request, **kwargs)
|
||||
|
||||
def prepare(self):
|
||||
super().prepare()
|
||||
if self._finished:
|
||||
return
|
||||
|
||||
if cfg.app_mode == APP_MODE_NORMAL:
|
||||
return
|
||||
|
||||
# self.redirect('/maintenance')
|
||||
self.render('maintenance/index.mako')
|
||||
|
||||
|
||||
class SwxJsonpHandler(SwxAppHandler):
|
||||
def __init__(self, application, request, **kwargs):
|
||||
super().__init__(application, request, **kwargs)
|
||||
|
||||
|
@ -89,6 +111,8 @@ class SwxJsonpHandler(SwxBaseHandler):
|
|||
|
||||
def prepare(self):
|
||||
super().prepare()
|
||||
if self._finished:
|
||||
return
|
||||
|
||||
self._js_callback = self.get_argument('callback', None)
|
||||
if self._js_callback is None:
|
||||
|
@ -112,13 +136,14 @@ class SwxJsonpHandler(SwxBaseHandler):
|
|||
self.write('})')
|
||||
|
||||
|
||||
class SwxJsonHandler(SwxBaseHandler):
|
||||
class SwxJsonHandler(SwxAppHandler):
|
||||
"""
|
||||
所有返回JSON数据的控制器均从本类集成,返回的数据格式一律包含三个字段:code/msg/data
|
||||
code: 0=成功,其他=失败
|
||||
msg: 字符串,一般用于code为非零是,指出错误原因
|
||||
msg: 字符串,一般用于code为非零,指出错误原因
|
||||
data: 一般用于成功操作的返回的业务数据
|
||||
"""
|
||||
|
||||
def __init__(self, application, request, **kwargs):
|
||||
super().__init__(application, request, **kwargs)
|
||||
|
||||
|
@ -131,7 +156,7 @@ class SwxJsonHandler(SwxBaseHandler):
|
|||
if data is None:
|
||||
data = list()
|
||||
|
||||
_ret = {'code':code, 'message':message, 'data':data}
|
||||
_ret = {'code': code, 'message': message, 'data': data}
|
||||
|
||||
self.set_header("Content-Type", "application/json")
|
||||
self.write(json_encode(_ret))
|
||||
|
@ -145,12 +170,14 @@ class SwxJsonHandler(SwxBaseHandler):
|
|||
self.write(json_encode(data))
|
||||
|
||||
|
||||
class SwxAuthHandler(SwxBaseHandler):
|
||||
class SwxAuthHandler(SwxAppHandler):
|
||||
def __init__(self, application, request, **kwargs):
|
||||
super().__init__(application, request, **kwargs)
|
||||
|
||||
def prepare(self):
|
||||
super().prepare()
|
||||
if self._finished:
|
||||
return
|
||||
|
||||
reference = self.request.uri
|
||||
|
||||
|
@ -163,12 +190,14 @@ class SwxAuthHandler(SwxBaseHandler):
|
|||
self.redirect('/auth/login')
|
||||
|
||||
|
||||
class SwxAdminHandler(SwxBaseHandler):
|
||||
class SwxAdminHandler(SwxAppHandler):
|
||||
def __init__(self, application, request, **kwargs):
|
||||
super().__init__(application, request, **kwargs)
|
||||
|
||||
def prepare(self):
|
||||
super().prepare()
|
||||
if self._finished:
|
||||
return
|
||||
|
||||
reference = self.request.uri
|
||||
|
||||
|
@ -181,9 +210,9 @@ class SwxAdminHandler(SwxBaseHandler):
|
|||
self.redirect('/auth/login')
|
||||
|
||||
|
||||
class SwxAuthJsonpHandler(SwxBaseHandler):
|
||||
def __init__(self, application, request, **kwargs):
|
||||
super().__init__(application, request, **kwargs)
|
||||
# class SwxAuthJsonpHandler(SwxAppHandler):
|
||||
# def __init__(self, application, request, **kwargs):
|
||||
# super().__init__(application, request, **kwargs)
|
||||
|
||||
|
||||
class SwxAuthJsonHandler(SwxJsonHandler):
|
||||
|
@ -192,16 +221,17 @@ class SwxAuthJsonHandler(SwxJsonHandler):
|
|||
|
||||
def prepare(self):
|
||||
super().prepare()
|
||||
if self._finished:
|
||||
return
|
||||
|
||||
reference = self.request.uri
|
||||
|
||||
user = self.get_current_user()
|
||||
if not user['is_login']:
|
||||
if reference != '/auth/login':
|
||||
x = quote(reference)
|
||||
self.redirect('/auth/login?ref={}'.format(x))
|
||||
self.write_json(-99)
|
||||
else:
|
||||
self.redirect('/auth/login')
|
||||
self.write_json(-99)
|
||||
|
||||
|
||||
class SwxAdminJsonHandler(SwxJsonHandler):
|
||||
|
@ -210,6 +240,8 @@ class SwxAdminJsonHandler(SwxJsonHandler):
|
|||
|
||||
def prepare(self):
|
||||
super().prepare()
|
||||
if self._finished:
|
||||
return
|
||||
|
||||
reference = self.request.uri
|
||||
|
||||
|
|
|
@ -83,7 +83,7 @@ class LoadFile(SwxAuthJsonHandler):
|
|||
"""
|
||||
ret = dict()
|
||||
ret['code'] = 0
|
||||
ret['msg'] = list() # 记录跳过的行(格式不正确,或者数据重复等)
|
||||
ret['msg'] = list() # 记录跳过的行(格式不正确,或者数据重复等)
|
||||
csv_filename = ''
|
||||
|
||||
try:
|
||||
|
@ -136,7 +136,7 @@ class LoadFile(SwxAuthJsonHandler):
|
|||
|
||||
# 格式错误则记录在案,然后继续
|
||||
if len(csv_recorder) != 13:
|
||||
ret['msg'].append({'reason':'格式错误', 'line':', '.join(csv_recorder)})
|
||||
ret['msg'].append({'reason': '格式错误', 'line': ', '.join(csv_recorder)})
|
||||
continue
|
||||
|
||||
# pro_type = int(line[6])
|
||||
|
@ -201,7 +201,7 @@ class LoadFile(SwxAuthJsonHandler):
|
|||
ret['msg'].append({'reason': '添加登录账号失败,账号已存在', 'line': ', '.join(csv_recorder)})
|
||||
else:
|
||||
ret['msg'].append({'reason': '添加登录账号失败,操作数据库失败', 'line': ', '.join(csv_recorder)})
|
||||
# log.e('sys_user_add() failed.\n')
|
||||
# log.e('sys_user_add() failed.\n')
|
||||
|
||||
ret = json.dumps(ret).encode('utf8')
|
||||
self.write(ret)
|
||||
|
@ -215,7 +215,7 @@ class LoadFile(SwxAuthJsonHandler):
|
|||
if os.path.exists(csv_filename):
|
||||
os.remove(csv_filename)
|
||||
|
||||
# self.write_json(0)
|
||||
# self.write_json(0)
|
||||
|
||||
|
||||
class GetListHandler(SwxAuthJsonHandler):
|
||||
|
@ -409,7 +409,7 @@ class ExportHost(SwxAuthJsonHandler):
|
|||
limit = dict()
|
||||
limit['page_index'] = 0
|
||||
limit['per_page'] = 999999
|
||||
_total, _hosts = host.get_all_host_info_list(dict(), order, limit,True)
|
||||
_total, _hosts = host.get_all_host_info_list(dict(), order, limit, True)
|
||||
export_file = os.path.join(cfg.static_path, 'download', 'export_csv_data.csv')
|
||||
if os.path.exists(export_file):
|
||||
os.remove(export_file)
|
||||
|
@ -809,7 +809,6 @@ class GetSessionId(SwxAuthJsonHandler):
|
|||
# ret = {'code':-1}
|
||||
self.write_json(-1)
|
||||
return
|
||||
values = dict()
|
||||
if 'auth_id' not in args:
|
||||
self.write_json(-1)
|
||||
return
|
||||
|
@ -826,9 +825,9 @@ class GetSessionId(SwxAuthJsonHandler):
|
|||
ts_server_rpc_ip = cfg.core.rpc.ip
|
||||
ts_server_rpc_port = cfg.core.rpc.port
|
||||
|
||||
url = 'http://{}:{}/request_session'.format(ts_server_rpc_ip, ts_server_rpc_port)
|
||||
values['auth_id'] = auth_id
|
||||
return_data = post_http(url, values)
|
||||
url = 'http://{}:{}/rpc'.format(ts_server_rpc_ip, ts_server_rpc_port)
|
||||
req = {'method': 'request_session', 'param': {'authid': auth_id}}
|
||||
return_data = post_http(url, req)
|
||||
if return_data is None:
|
||||
return self.write_json(-1)
|
||||
return_data = json.loads(return_data)
|
||||
|
@ -1113,7 +1112,6 @@ class SysUserDelete(SwxAuthJsonHandler):
|
|||
return
|
||||
|
||||
if host.sys_user_delete(host_auth_id):
|
||||
return self.write_json(0)
|
||||
return self.write_json(0)
|
||||
|
||||
return self.write_json(-1)
|
||||
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# import sys
|
||||
# import tornado.ioloop
|
||||
from .base import SwxBaseHandler
|
||||
|
||||
|
||||
class IndexHandler(SwxBaseHandler):
|
||||
def get(self):
|
||||
self.render('maintenance/index.mako')
|
||||
|
|
@ -0,0 +1,94 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
import tornado.web
|
||||
import tornado.gen
|
||||
|
||||
import json
|
||||
import urllib.parse
|
||||
from eom_app.module import host
|
||||
|
||||
from .base import SwxJsonHandler
|
||||
|
||||
|
||||
class RpcHandler(SwxJsonHandler):
|
||||
@tornado.web.asynchronous
|
||||
@tornado.gen.coroutine
|
||||
def get(self):
|
||||
_uri = self.request.uri.split('?', 1)
|
||||
print(_uri)
|
||||
if len(_uri) != 2:
|
||||
self.write_json(-1, message='need request param.')
|
||||
return
|
||||
|
||||
self._dispatch(urllib.parse.unquote(_uri[1]))
|
||||
|
||||
def post(self):
|
||||
# curl -X POST --data '{"method":"get_auth_info","param":{"authid":0}}' http://127.0.0.1:7190/rpc
|
||||
req = self.request.body.decode('utf-8')
|
||||
if req == '':
|
||||
self.write_json(-1, message='need request param.')
|
||||
return
|
||||
|
||||
self._dispatch(req)
|
||||
|
||||
def _dispatch(self, req):
|
||||
print('rpc-req:', req)
|
||||
try:
|
||||
_req = json.loads(req)
|
||||
|
||||
if 'method' not in _req or 'param' not in _req:
|
||||
self.write_json(-1, message='invalid request format.')
|
||||
return
|
||||
|
||||
except:
|
||||
self.write_json(-1, message='invalid json format.')
|
||||
return
|
||||
|
||||
if 'get_auth_info' == _req['method']:
|
||||
return self._get_auth_info(_req['param'])
|
||||
elif 'session_begin' == _req['method']:
|
||||
return self._session_begin(_req['param'])
|
||||
elif 'session_end' == _req['method']:
|
||||
return self._session_end(_req['param'])
|
||||
elif 'session_fix' == _req['method']:
|
||||
return self._session_fix()
|
||||
elif 'exit' == _req['method']:
|
||||
return self._exit()
|
||||
|
||||
self.write_json(-1, message='invalid method.')
|
||||
|
||||
def _get_auth_info(self, param):
|
||||
# todo: 如果是页面上进行连接测试(增加或修改主机和用户时),信息并不写入数据库,而是在内存中存在,传递给core服务的
|
||||
# 应该是随机字符串做authid,名称为 tauthid。本接口应该支持区分这两种认证ID。
|
||||
|
||||
if 'authid' not in param:
|
||||
self.write_json(-1, message='invalid request.')
|
||||
return
|
||||
|
||||
# 根据authid从数据库中查询对应的数据,然后返回给调用者
|
||||
x = host.get_auth_info(param['authid'])
|
||||
print('get_auth_info():', x)
|
||||
|
||||
self.write_json(0, data=x)
|
||||
|
||||
def _session_begin(self, param):
|
||||
if 'sid' not in param:
|
||||
self.write_json(-1, message='invalid request.')
|
||||
return
|
||||
|
||||
self.write_json(0, data={'rid': 12})
|
||||
|
||||
def _session_end(self, param):
|
||||
if 'rid' not in param or 'code' not in param:
|
||||
self.write_json(-1, message='invalid request.')
|
||||
return
|
||||
|
||||
self.write_json(0)
|
||||
|
||||
def _session_fix(self):
|
||||
# do db operation.
|
||||
self.write_json(0)
|
||||
|
||||
def _exit(self):
|
||||
# set exit flag.
|
||||
self.write_json(0)
|
|
@ -1,15 +1,10 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
# from eom_common.eomcore.utils import *
|
||||
from .common import *
|
||||
import time
|
||||
|
||||
|
||||
# import eom_common.eomcore.eom_mysql as mysql
|
||||
# import sqlite3
|
||||
|
||||
|
||||
# 获取主机列表,包括主机的基本信息(CPU型号、内存大小、磁盘大小,未激活的主机编号也会返回)
|
||||
# 获取主机列表,包括主机的基本信息
|
||||
def get_all_host_info_list(filter, order, limit, with_pwd=False):
|
||||
sql_exec = get_db_con()
|
||||
|
||||
|
@ -43,7 +38,7 @@ def get_all_host_info_list(filter, order, limit, with_pwd=False):
|
|||
_where += ')'
|
||||
|
||||
# http://www.jb51.net/article/46015.htm
|
||||
field_a = ['host_id', 'host_lock', 'host_ip','host_port', 'protocol', 'host_desc', 'group_id', 'host_sys_type']
|
||||
field_a = ['host_id', 'host_lock', 'host_ip', 'host_port', 'protocol', 'host_desc', 'group_id', 'host_sys_type']
|
||||
field_b = ['group_name']
|
||||
|
||||
# field_c = ['id', 'auth_mode', 'user_name']
|
||||
|
@ -173,12 +168,12 @@ def get_host_info_list_by_user(filter, order, limit):
|
|||
|
||||
# http://www.jb51.net/article/46015.htm
|
||||
field_a = ['auth_id', 'host_id', 'account_name', 'host_auth_id']
|
||||
field_b = ['host_id', 'host_lock', 'host_ip', 'protocol', 'host_port', 'host_desc', 'group_id', 'host_sys_type']
|
||||
field_b = ['host_id', 'host_lock', 'host_ip', 'protocol', 'host_port', 'host_desc', 'group_id', 'host_sys_type']
|
||||
field_c = ['group_name']
|
||||
field_d = ['auth_mode', 'user_name']
|
||||
str_sql = 'SELECT COUNT(DISTINCT a.host_id) ' \
|
||||
'FROM ts_auth AS a ' \
|
||||
'LEFT JOIN ts_host_info AS b ON a.host_id = b.host_id '\
|
||||
'LEFT JOIN ts_host_info AS b ON a.host_id = b.host_id ' \
|
||||
'{};'.format(_where)
|
||||
|
||||
db_ret = sql_exec.ExecProcQuery(str_sql)
|
||||
|
@ -232,7 +227,7 @@ def get_host_info_list_by_user(filter, order, limit):
|
|||
host_ip = x.b_host_ip
|
||||
protocol = x.b_protocol
|
||||
key = '{}-{}'.format(host_ip, protocol)
|
||||
temp_auth = None
|
||||
temp_auth = None
|
||||
extend_auth_list = sys_user_list(x.b_host_id, False, x.a_host_auth_id)
|
||||
if extend_auth_list is not None and len(extend_auth_list) > 0:
|
||||
auth = extend_auth_list[0]
|
||||
|
@ -373,7 +368,7 @@ def add_host(args, must_not_exists=True):
|
|||
host_port = args['host_port']
|
||||
host_ip = args['host_ip']
|
||||
|
||||
str_sql = 'SELECT host_id FROM ts_host_info WHERE (host_ip=\'{}\' and protocol={} and host_port={});'\
|
||||
str_sql = 'SELECT host_id FROM ts_host_info WHERE (host_ip=\'{}\' and protocol={} and host_port={});' \
|
||||
.format(host_ip, protocol, host_port)
|
||||
db_ret = sql_exec.ExecProcQuery(str_sql)
|
||||
if db_ret is not None and len(db_ret) > 0:
|
||||
|
@ -521,7 +516,7 @@ def get_host_auth_info(host_auth_id):
|
|||
sql_exec = get_db_con()
|
||||
|
||||
field_a = ['id', 'auth_mode', 'user_name', 'user_pswd', 'user_param', 'cert_id', 'encrypt']
|
||||
field_b = ['host_id', 'host_lock', 'host_ip', 'host_port', 'host_desc', 'group_id', 'host_sys_type', 'protocol']
|
||||
field_b = ['host_id', 'host_lock', 'host_ip', 'host_port', 'host_desc', 'group_id', 'host_sys_type', 'protocol']
|
||||
|
||||
str_sql = 'SELECT {},{} ' \
|
||||
'FROM ts_auth_info AS a ' \
|
||||
|
@ -564,7 +559,7 @@ def get_host_auth_info(host_auth_id):
|
|||
if x.a_cert_id is None:
|
||||
cert_id = 0
|
||||
else:
|
||||
cert_id = int(x.a_cert_id) #int(user_auth)
|
||||
cert_id = int(x.a_cert_id) # int(user_auth)
|
||||
str_sql = 'SELECT cert_pri FROM ts_cert WHERE cert_id = {}'.format(cert_id)
|
||||
db_ret = sql_exec.ExecProcQuery(str_sql)
|
||||
if db_ret is not None and len(db_ret) == 1:
|
||||
|
@ -677,7 +672,7 @@ def sys_user_list(host_id, with_pwd=True, host_auth_id=0):
|
|||
|
||||
|
||||
def GetNowTime():
|
||||
return time.strftime("%Y-%m-%d %H:%M:%S",time.localtime(time.time()))
|
||||
return time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(time.time()))
|
||||
|
||||
|
||||
def sys_user_add(args):
|
||||
|
@ -697,7 +692,7 @@ def sys_user_add(args):
|
|||
sql_exec = get_db_con()
|
||||
|
||||
# 判断此登录账号是否已经存在,如果存在则报错
|
||||
str_sql = 'SELECT id FROM ts_auth_info WHERE (host_id={} and auth_mode={} and user_name=\'{}\');'\
|
||||
str_sql = 'SELECT id FROM ts_auth_info WHERE (host_id={} and auth_mode={} and user_name=\'{}\');' \
|
||||
.format(host_id, auth_mode, user_name)
|
||||
db_ret = sql_exec.ExecProcQuery(str_sql)
|
||||
if db_ret is not None and len(db_ret) > 0:
|
||||
|
@ -708,7 +703,7 @@ def sys_user_add(args):
|
|||
if auth_mode == 1:
|
||||
str_sql = 'INSERT INTO ts_auth_info (host_id, auth_mode, user_name, user_pswd, user_param,' \
|
||||
'encrypt, cert_id, log_time) ' \
|
||||
'VALUES ({},{},\'{}\',\'{}\',\'{}\',{}, {},\'{}\')'.format(host_id, auth_mode, user_name, user_pswd, user_param,encrypt, 0, log_time)
|
||||
'VALUES ({},{},\'{}\',\'{}\',\'{}\',{}, {},\'{}\')'.format(host_id, auth_mode, user_name, user_pswd, user_param, encrypt, 0, log_time)
|
||||
elif auth_mode == 2:
|
||||
str_sql = 'INSERT INTO ts_auth_info (host_id, auth_mode, user_name,user_param, ' \
|
||||
'user_pswd,cert_id, encrypt, log_time) ' \
|
||||
|
@ -724,7 +719,6 @@ def sys_user_add(args):
|
|||
if not ret:
|
||||
return -101
|
||||
|
||||
|
||||
str_sql = 'select last_insert_rowid()'
|
||||
db_ret = sql_exec.ExecProcQuery(str_sql)
|
||||
if db_ret is None:
|
||||
|
@ -752,15 +746,91 @@ def sys_user_update(_id, kv):
|
|||
return db_ret
|
||||
|
||||
|
||||
def sys_user_delete(id):
|
||||
def sys_user_delete(_id):
|
||||
sql_exec = get_db_con()
|
||||
try:
|
||||
str_sql = 'DELETE FROM ts_auth_info WHERE id = {} '.format(id)
|
||||
str_sql = 'DELETE FROM ts_auth_info WHERE id = {} '.format(_id)
|
||||
ret = sql_exec.ExecProcNonQuery(str_sql)
|
||||
|
||||
str_sql = 'DELETE FROM ts_auth WHERE host_auth_id = {} '.format(id)
|
||||
str_sql = 'DELETE FROM ts_auth WHERE host_auth_id = {} '.format(_id)
|
||||
ret = sql_exec.ExecProcNonQuery(str_sql)
|
||||
except Exception as e:
|
||||
return False
|
||||
|
||||
return True
|
||||
return True
|
||||
|
||||
|
||||
def get_auth_info(auth_id):
|
||||
"""
|
||||
根据指定的auth_id查询相关的认证信息(远程主机IP、端口、登录用户名、登录密码或私钥,等等)
|
||||
@param auth_id: integer
|
||||
@return:
|
||||
"""
|
||||
sql_exec = get_db_con()
|
||||
|
||||
field_a = ['auth_id', 'account_name', 'host_auth_id', 'host_id']
|
||||
field_b = ['host_sys_type', 'host_ip', 'host_port', 'protocol']
|
||||
field_c = ['user_pswd', 'cert_id', 'user_name', 'encrypt', 'auth_mode', 'user_param']
|
||||
field_d = ['account_lock']
|
||||
|
||||
str_sql = 'SELECT {},{},{},{} ' \
|
||||
'FROM ts_auth AS a ' \
|
||||
'LEFT JOIN ts_host_info AS b ON a.host_id = b.host_id ' \
|
||||
'LEFT JOIN ts_auth_info AS c ON a.host_auth_id = c.id ' \
|
||||
'LEFT JOIN ts_account AS d ON a.account_name = d.account_name ' \
|
||||
'WHERE a.auth_id={};'.format(
|
||||
','.join(['a.{}'.format(i) for i in field_a]),
|
||||
','.join(['b.{}'.format(i) for i in field_b]),
|
||||
','.join(['c.{}'.format(i) for i in field_c]),
|
||||
','.join(['d.{}'.format(i) for i in field_d]),
|
||||
auth_id)
|
||||
|
||||
print(str_sql)
|
||||
|
||||
"""
|
||||
"SELECT a.auth_id as auth_id, a.account_name as account_name, \
|
||||
// a.host_auth_id as host_auth_id, a.host_id as host_id,host_lock, \
|
||||
// b.host_sys_type as host_sys_type, host_ip, host_port, protocol, \
|
||||
// c.user_pswd as user_pswd, c.cert_id as cert_id, c.user_name as user_name, \
|
||||
// c.encrypt as encrypt, c.auth_mode as auth_mode,c.user_param as user_param, \
|
||||
// d.account_lock as account_lock FROM ts_auth as a \
|
||||
// LEFT JOIN ts_host_info as b ON a.host_id = b.host_id \
|
||||
// LEFT JOIN ts_auth_info as c ON a.host_auth_id = c.id \
|
||||
// LEFT JOIN ts_account as d ON a.account_name = d.account_name \
|
||||
// WHERE a.auth_id=%d", auth_id
|
||||
"""
|
||||
|
||||
db_ret = sql_exec.ExecProcQuery(str_sql)
|
||||
|
||||
if db_ret is None:
|
||||
return None
|
||||
ret = list()
|
||||
for item in db_ret:
|
||||
x = DbItem()
|
||||
|
||||
x.load(item,
|
||||
['a_{}'.format(i) for i in field_a] +
|
||||
['b_{}'.format(i) for i in field_b] +
|
||||
['c_{}'.format(i) for i in field_c] +
|
||||
['d_{}'.format(i) for i in field_d]
|
||||
)
|
||||
|
||||
h = dict()
|
||||
h['host_ip'] = x.b_host_ip
|
||||
h['sys_type'] = x.b_host_sys_type
|
||||
h['account_name'] = x.a_account_name
|
||||
h['account_lock'] = x.d_account_lock
|
||||
# h['host_lock'] = x.a_host_lock
|
||||
h['host_port'] = x.b_host_port
|
||||
h['protocol'] = x.b_protocol
|
||||
h['encrypt'] = x.c_encrypt
|
||||
h['auth_mode'] = x.c_auth_mode
|
||||
h['user_name'] = x.c_user_name
|
||||
h['user_param'] = x.c_user_param
|
||||
h['user_pswd'] = x.c_user_pswd
|
||||
h['cert_id'] = x.c_cert_id
|
||||
|
||||
ret.append(h)
|
||||
|
||||
print(ret)
|
||||
return ret
|
||||
|
|
|
@ -1,6 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""EOM Algorithm Package."""
|
||||
|
||||
__version__ = '1.0.1'
|
||||
|
Binary file not shown.
|
@ -1,97 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""DES"""
|
||||
|
||||
import os
|
||||
from ctypes import *
|
||||
|
||||
use_alg = True
|
||||
|
||||
try:
|
||||
# Try to locate the .so file in the same directory as this file
|
||||
_file = 'alg.dll'
|
||||
_path = os.path.join(*(os.path.split(__file__)[:-1] + (_file,)))
|
||||
_mod = cdll.LoadLibrary(_path)
|
||||
|
||||
_des3_cbc_encrypt = _mod.des3_cbc_encrypt
|
||||
_des3_cbc_encrypt.argtypes = (c_void_p, c_int, c_void_p, c_int, c_void_p)
|
||||
_des3_cbc_encrypt.restype = c_int
|
||||
|
||||
_des3_cbc_decrypt = _mod.des3_cbc_decrypt
|
||||
_des3_cbc_decrypt.argtypes = (c_void_p, c_int, c_void_p, c_int, c_void_p)
|
||||
_des3_cbc_decrypt.restype = c_int
|
||||
|
||||
_free_buffer = _mod.free_buffer
|
||||
_free_buffer.argtypes = (c_void_p,)
|
||||
|
||||
except OSError as e:
|
||||
use_alg = False
|
||||
from eom_common.eomcore.algorithm import pyDes
|
||||
# raise RuntimeError('kx')
|
||||
# print('xxxxxxxxxx')
|
||||
# pass
|
||||
|
||||
|
||||
def print_bin(data):
|
||||
for i in range(len(data)):
|
||||
print('%02X ' % data[i], end='')
|
||||
if (i + 1) % 16 == 0:
|
||||
print('')
|
||||
print('')
|
||||
|
||||
|
||||
def des3_cbc_encrypt(key, plain_data):
|
||||
if use_alg:
|
||||
|
||||
out = POINTER(c_ubyte)()
|
||||
out_len = _des3_cbc_encrypt(key, len(key), plain_data, len(plain_data), byref(out))
|
||||
if out_len < 0:
|
||||
return None
|
||||
|
||||
ret = bytes(cast(out, POINTER(c_ubyte * out_len)).contents)
|
||||
_free_buffer(out)
|
||||
|
||||
return ret
|
||||
else:
|
||||
try:
|
||||
return pyDes.triple_des(key, pyDes.CBC, b'\x00'*8).encrypt(plain_data, None, pyDes.PAD_PKCS5)
|
||||
except Exception:
|
||||
return None
|
||||
|
||||
|
||||
def des3_cbc_decrypt(key, enc_data):
|
||||
if use_alg:
|
||||
|
||||
out = POINTER(c_ubyte)()
|
||||
out_len = _des3_cbc_decrypt(key, len(key), enc_data, len(enc_data), byref(out))
|
||||
if out_len < 0:
|
||||
return None
|
||||
|
||||
ret = bytes(cast(out, POINTER(c_ubyte * out_len)).contents)
|
||||
_free_buffer(out)
|
||||
|
||||
return ret
|
||||
else:
|
||||
try:
|
||||
return pyDes.triple_des(key, pyDes.CBC, b'\x00'*8).decrypt(enc_data, None, pyDes.PAD_PKCS5)
|
||||
except Exception:
|
||||
return None
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
key = b'\x00' * 24
|
||||
plain_data = os.urandom(110)
|
||||
print_bin(plain_data)
|
||||
|
||||
try:
|
||||
enc = des3_cbc_encrypt(key, plain_data)
|
||||
print('==========================')
|
||||
print_bin(enc)
|
||||
print('==========================')
|
||||
dec = des3_cbc_decrypt(key, enc)
|
||||
print('==========================')
|
||||
print_bin(dec)
|
||||
print('==========================')
|
||||
except Exception:
|
||||
print('error')
|
||||
raise
|
|
@ -1 +0,0 @@
|
|||
__author__ = 'apex'
|
|
@ -1,853 +0,0 @@
|
|||
#############################################################################
|
||||
# Documentation #
|
||||
#############################################################################
|
||||
|
||||
# Author: Todd Whiteman
|
||||
# Date: 16th March, 2009
|
||||
# Verion: 2.0.0
|
||||
# License: Public Domain - free to do as you wish
|
||||
# Homepage: http://twhiteman.netfirms.com/des.html
|
||||
#
|
||||
# This is a pure python implementation of the DES encryption algorithm.
|
||||
# It's pure python to avoid portability issues, since most DES
|
||||
# implementations are programmed in C (for performance reasons).
|
||||
#
|
||||
# Triple DES class is also implemented, utilising the DES base. Triple DES
|
||||
# is either DES-EDE3 with a 24 byte key, or DES-EDE2 with a 16 byte key.
|
||||
#
|
||||
# See the README.txt that should come with this python module for the
|
||||
# implementation methods used.
|
||||
#
|
||||
# Thanks to:
|
||||
# * David Broadwell for ideas, comments and suggestions.
|
||||
# * Mario Wolff for pointing out and debugging some triple des CBC errors.
|
||||
# * Santiago Palladino for providing the PKCS5 padding technique.
|
||||
# * Shaya for correcting the PAD_PKCS5 triple des CBC errors.
|
||||
#
|
||||
"""A pure python implementation of the DES and TRIPLE DES encryption algorithms.
|
||||
|
||||
Class initialization
|
||||
--------------------
|
||||
pyDes.des(key, [mode], [IV], [pad], [padmode])
|
||||
pyDes.triple_des(key, [mode], [IV], [pad], [padmode])
|
||||
|
||||
key -> Bytes containing the encryption key. 8 bytes for DES, 16 or 24 bytes
|
||||
for Triple DES
|
||||
mode -> Optional argument for encryption type, can be either
|
||||
pyDes.ECB (Electronic Code Book) or pyDes.CBC (Cypher Block Chaining)
|
||||
IV -> Optional Initial Value bytes, must be supplied if using CBC mode.
|
||||
Length must be 8 bytes.
|
||||
pad -> Optional argument, set the pad character (PAD_NORMAL) to use during
|
||||
all encrypt/decrpt operations done with this instance.
|
||||
padmode -> Optional argument, set the padding mode (PAD_NORMAL or PAD_PKCS5)
|
||||
to use during all encrypt/decrpt operations done with this instance.
|
||||
|
||||
I recommend to use PAD_PKCS5 padding, as then you never need to worry about any
|
||||
padding issues, as the padding can be removed unambiguously upon decrypting
|
||||
data that was encrypted using PAD_PKCS5 padmode.
|
||||
|
||||
Common methods
|
||||
--------------
|
||||
encrypt(data, [pad], [padmode])
|
||||
decrypt(data, [pad], [padmode])
|
||||
|
||||
data -> Bytes to be encrypted/decrypted
|
||||
pad -> Optional argument. Only when using padmode of PAD_NORMAL. For
|
||||
encryption, adds this characters to the end of the data block when
|
||||
data is not a multiple of 8 bytes. For decryption, will remove the
|
||||
trailing characters that match this pad character from the last 8
|
||||
bytes of the unencrypted data block.
|
||||
padmode -> Optional argument, set the padding mode, must be one of PAD_NORMAL
|
||||
or PAD_PKCS5). Defaults to PAD_NORMAL.
|
||||
|
||||
|
||||
Example
|
||||
-------
|
||||
from pyDes import *
|
||||
|
||||
data = "Please encrypt my data"
|
||||
k = des("DESCRYPT", CBC, "\0\0\0\0\0\0\0\0", pad=None, padmode=PAD_PKCS5)
|
||||
# For Python3, you'll need to use bytes, i.e.:
|
||||
# data = b"Please encrypt my data"
|
||||
# k = des(b"DESCRYPT", CBC, b"\0\0\0\0\0\0\0\0", pad=None, padmode=PAD_PKCS5)
|
||||
d = k.encrypt(data)
|
||||
print "Encrypted: %r" % d
|
||||
print "Decrypted: %r" % k.decrypt(d)
|
||||
assert k.decrypt(d, padmode=PAD_PKCS5) == data
|
||||
|
||||
|
||||
See the module source (pyDes.py) for more examples of use.
|
||||
You can also run the pyDes.py file without and arguments to see a simple test.
|
||||
|
||||
Note: This code was not written for high-end systems needing a fast
|
||||
implementation, but rather a handy portable solution with small usage.
|
||||
|
||||
"""
|
||||
|
||||
import sys
|
||||
|
||||
# _pythonMajorVersion is used to handle Python2 and Python3 differences.
|
||||
_pythonMajorVersion = sys.version_info[0]
|
||||
|
||||
# Modes of crypting / cyphering
|
||||
ECB = 0
|
||||
CBC = 1
|
||||
|
||||
# Modes of padding
|
||||
PAD_NORMAL = 1
|
||||
PAD_PKCS5 = 2
|
||||
|
||||
|
||||
# PAD_PKCS5: is a method that will unambiguously remove all padding
|
||||
# characters after decryption, when originally encrypted with
|
||||
# this padding mode.
|
||||
# For a good description of the PKCS5 padding technique, see:
|
||||
# http://www.faqs.org/rfcs/rfc1423.html
|
||||
|
||||
# The base class shared by des and triple des.
|
||||
class _baseDes(object):
|
||||
def __init__(self, mode=ECB, IV=None, pad=None, padmode=PAD_NORMAL):
|
||||
if IV:
|
||||
IV = self._guardAgainstUnicode(IV)
|
||||
if pad:
|
||||
pad = self._guardAgainstUnicode(pad)
|
||||
self.block_size = 8
|
||||
# Sanity checking of arguments.
|
||||
if pad and padmode == PAD_PKCS5:
|
||||
raise ValueError("Cannot use a pad character with PAD_PKCS5")
|
||||
if IV and len(IV) != self.block_size:
|
||||
raise ValueError("Invalid Initial Value (IV), must be a multiple of " + str(self.block_size) + " bytes")
|
||||
|
||||
# Set the passed in variables
|
||||
self._mode = mode
|
||||
self._iv = IV
|
||||
self._padding = pad
|
||||
self._padmode = padmode
|
||||
|
||||
def getKey(self):
|
||||
"""getKey() -> bytes"""
|
||||
return self.__key
|
||||
|
||||
def setKey(self, key):
|
||||
"""Will set the crypting key for this object."""
|
||||
key = self._guardAgainstUnicode(key)
|
||||
self.__key = key
|
||||
|
||||
def getMode(self):
|
||||
"""getMode() -> pyDes.ECB or pyDes.CBC"""
|
||||
return self._mode
|
||||
|
||||
def setMode(self, mode):
|
||||
"""Sets the type of crypting mode, pyDes.ECB or pyDes.CBC"""
|
||||
self._mode = mode
|
||||
|
||||
def getPadding(self):
|
||||
"""getPadding() -> bytes of length 1. Padding character."""
|
||||
return self._padding
|
||||
|
||||
def setPadding(self, pad):
|
||||
"""setPadding() -> bytes of length 1. Padding character."""
|
||||
if pad is not None:
|
||||
pad = self._guardAgainstUnicode(pad)
|
||||
self._padding = pad
|
||||
|
||||
def getPadMode(self):
|
||||
"""getPadMode() -> pyDes.PAD_NORMAL or pyDes.PAD_PKCS5"""
|
||||
return self._padmode
|
||||
|
||||
def setPadMode(self, mode):
|
||||
"""Sets the type of padding mode, pyDes.PAD_NORMAL or pyDes.PAD_PKCS5"""
|
||||
self._padmode = mode
|
||||
|
||||
def getIV(self):
|
||||
"""getIV() -> bytes"""
|
||||
return self._iv
|
||||
|
||||
def setIV(self, IV):
|
||||
"""Will set the Initial Value, used in conjunction with CBC mode"""
|
||||
if not IV or len(IV) != self.block_size:
|
||||
raise ValueError("Invalid Initial Value (IV), must be a multiple of " + str(self.block_size) + " bytes")
|
||||
IV = self._guardAgainstUnicode(IV)
|
||||
self._iv = IV
|
||||
|
||||
def _padData(self, data, pad, padmode):
|
||||
# Pad data depending on the mode
|
||||
if padmode is None:
|
||||
# Get the default padding mode.
|
||||
padmode = self.getPadMode()
|
||||
if pad and padmode == PAD_PKCS5:
|
||||
raise ValueError("Cannot use a pad character with PAD_PKCS5")
|
||||
|
||||
if padmode == PAD_NORMAL:
|
||||
if len(data) % self.block_size == 0:
|
||||
# No padding required.
|
||||
return data
|
||||
|
||||
if not pad:
|
||||
# Get the default padding.
|
||||
pad = self.getPadding()
|
||||
if not pad:
|
||||
raise ValueError("Data must be a multiple of " + str(self.block_size) + " bytes in length. Use padmode=PAD_PKCS5 or set the pad character.")
|
||||
data += (self.block_size - (len(data) % self.block_size)) * pad
|
||||
|
||||
elif padmode == PAD_PKCS5:
|
||||
pad_len = 8 - (len(data) % self.block_size)
|
||||
if _pythonMajorVersion < 3:
|
||||
data += pad_len * chr(pad_len)
|
||||
else:
|
||||
data += bytes([pad_len] * pad_len)
|
||||
|
||||
return data
|
||||
|
||||
def _unpadData(self, data, pad, padmode):
|
||||
# Unpad data depending on the mode.
|
||||
if not data:
|
||||
return data
|
||||
if pad and padmode == PAD_PKCS5:
|
||||
raise ValueError("Cannot use a pad character with PAD_PKCS5")
|
||||
if padmode is None:
|
||||
# Get the default padding mode.
|
||||
padmode = self.getPadMode()
|
||||
|
||||
if padmode == PAD_NORMAL:
|
||||
if not pad:
|
||||
# Get the default padding.
|
||||
pad = self.getPadding()
|
||||
if pad:
|
||||
data = data[:-self.block_size] + \
|
||||
data[-self.block_size:].rstrip(pad)
|
||||
|
||||
elif padmode == PAD_PKCS5:
|
||||
if _pythonMajorVersion < 3:
|
||||
pad_len = ord(data[-1])
|
||||
else:
|
||||
pad_len = data[-1]
|
||||
data = data[:-pad_len]
|
||||
|
||||
return data
|
||||
|
||||
def _guardAgainstUnicode(self, data):
|
||||
# Only accept byte strings or ascii unicode values, otherwise
|
||||
# there is no way to correctly decode the data into bytes.
|
||||
if _pythonMajorVersion < 3:
|
||||
if isinstance(data, unicode):
|
||||
raise ValueError("pyDes can only work with bytes, not Unicode strings.")
|
||||
else:
|
||||
if isinstance(data, str):
|
||||
# Only accept ascii unicode values.
|
||||
try:
|
||||
return data.encode('ascii')
|
||||
except UnicodeEncodeError:
|
||||
pass
|
||||
raise ValueError("pyDes can only work with encoded strings, not Unicode.")
|
||||
return data
|
||||
|
||||
|
||||
#############################################################################
|
||||
# DES #
|
||||
#############################################################################
|
||||
class des(_baseDes):
|
||||
"""DES encryption/decrytpion class
|
||||
|
||||
Supports ECB (Electronic Code Book) and CBC (Cypher Block Chaining) modes.
|
||||
|
||||
pyDes.des(key,[mode], [IV])
|
||||
|
||||
key -> Bytes containing the encryption key, must be exactly 8 bytes
|
||||
mode -> Optional argument for encryption type, can be either pyDes.ECB
|
||||
(Electronic Code Book), pyDes.CBC (Cypher Block Chaining)
|
||||
IV -> Optional Initial Value bytes, must be supplied if using CBC mode.
|
||||
Must be 8 bytes in length.
|
||||
pad -> Optional argument, set the pad character (PAD_NORMAL) to use
|
||||
during all encrypt/decrpt operations done with this instance.
|
||||
padmode -> Optional argument, set the padding mode (PAD_NORMAL or
|
||||
PAD_PKCS5) to use during all encrypt/decrpt operations done
|
||||
with this instance.
|
||||
"""
|
||||
|
||||
|
||||
# Permutation and translation tables for DES
|
||||
__pc1 = [56, 48, 40, 32, 24, 16, 8,
|
||||
0, 57, 49, 41, 33, 25, 17,
|
||||
9, 1, 58, 50, 42, 34, 26,
|
||||
18, 10, 2, 59, 51, 43, 35,
|
||||
62, 54, 46, 38, 30, 22, 14,
|
||||
6, 61, 53, 45, 37, 29, 21,
|
||||
13, 5, 60, 52, 44, 36, 28,
|
||||
20, 12, 4, 27, 19, 11, 3
|
||||
]
|
||||
|
||||
# number left rotations of pc1
|
||||
__left_rotations = [
|
||||
1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1
|
||||
]
|
||||
|
||||
# permuted choice key (table 2)
|
||||
__pc2 = [
|
||||
13, 16, 10, 23, 0, 4,
|
||||
2, 27, 14, 5, 20, 9,
|
||||
22, 18, 11, 3, 25, 7,
|
||||
15, 6, 26, 19, 12, 1,
|
||||
40, 51, 30, 36, 46, 54,
|
||||
29, 39, 50, 44, 32, 47,
|
||||
43, 48, 38, 55, 33, 52,
|
||||
45, 41, 49, 35, 28, 31
|
||||
]
|
||||
|
||||
# initial permutation IP
|
||||
__ip = [57, 49, 41, 33, 25, 17, 9, 1,
|
||||
59, 51, 43, 35, 27, 19, 11, 3,
|
||||
61, 53, 45, 37, 29, 21, 13, 5,
|
||||
63, 55, 47, 39, 31, 23, 15, 7,
|
||||
56, 48, 40, 32, 24, 16, 8, 0,
|
||||
58, 50, 42, 34, 26, 18, 10, 2,
|
||||
60, 52, 44, 36, 28, 20, 12, 4,
|
||||
62, 54, 46, 38, 30, 22, 14, 6
|
||||
]
|
||||
|
||||
# Expansion table for turning 32 bit blocks into 48 bits
|
||||
__expansion_table = [
|
||||
31, 0, 1, 2, 3, 4,
|
||||
3, 4, 5, 6, 7, 8,
|
||||
7, 8, 9, 10, 11, 12,
|
||||
11, 12, 13, 14, 15, 16,
|
||||
15, 16, 17, 18, 19, 20,
|
||||
19, 20, 21, 22, 23, 24,
|
||||
23, 24, 25, 26, 27, 28,
|
||||
27, 28, 29, 30, 31, 0
|
||||
]
|
||||
|
||||
# The (in)famous S-boxes
|
||||
__sbox = [
|
||||
# S1
|
||||
[14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7,
|
||||
0, 15, 7, 4, 14, 2, 13, 1, 10, 6, 12, 11, 9, 5, 3, 8,
|
||||
4, 1, 14, 8, 13, 6, 2, 11, 15, 12, 9, 7, 3, 10, 5, 0,
|
||||
15, 12, 8, 2, 4, 9, 1, 7, 5, 11, 3, 14, 10, 0, 6, 13],
|
||||
|
||||
# S2
|
||||
[15, 1, 8, 14, 6, 11, 3, 4, 9, 7, 2, 13, 12, 0, 5, 10,
|
||||
3, 13, 4, 7, 15, 2, 8, 14, 12, 0, 1, 10, 6, 9, 11, 5,
|
||||
0, 14, 7, 11, 10, 4, 13, 1, 5, 8, 12, 6, 9, 3, 2, 15,
|
||||
13, 8, 10, 1, 3, 15, 4, 2, 11, 6, 7, 12, 0, 5, 14, 9],
|
||||
|
||||
# S3
|
||||
[10, 0, 9, 14, 6, 3, 15, 5, 1, 13, 12, 7, 11, 4, 2, 8,
|
||||
13, 7, 0, 9, 3, 4, 6, 10, 2, 8, 5, 14, 12, 11, 15, 1,
|
||||
13, 6, 4, 9, 8, 15, 3, 0, 11, 1, 2, 12, 5, 10, 14, 7,
|
||||
1, 10, 13, 0, 6, 9, 8, 7, 4, 15, 14, 3, 11, 5, 2, 12],
|
||||
|
||||
# S4
|
||||
[7, 13, 14, 3, 0, 6, 9, 10, 1, 2, 8, 5, 11, 12, 4, 15,
|
||||
13, 8, 11, 5, 6, 15, 0, 3, 4, 7, 2, 12, 1, 10, 14, 9,
|
||||
10, 6, 9, 0, 12, 11, 7, 13, 15, 1, 3, 14, 5, 2, 8, 4,
|
||||
3, 15, 0, 6, 10, 1, 13, 8, 9, 4, 5, 11, 12, 7, 2, 14],
|
||||
|
||||
# S5
|
||||
[2, 12, 4, 1, 7, 10, 11, 6, 8, 5, 3, 15, 13, 0, 14, 9,
|
||||
14, 11, 2, 12, 4, 7, 13, 1, 5, 0, 15, 10, 3, 9, 8, 6,
|
||||
4, 2, 1, 11, 10, 13, 7, 8, 15, 9, 12, 5, 6, 3, 0, 14,
|
||||
11, 8, 12, 7, 1, 14, 2, 13, 6, 15, 0, 9, 10, 4, 5, 3],
|
||||
|
||||
# S6
|
||||
[12, 1, 10, 15, 9, 2, 6, 8, 0, 13, 3, 4, 14, 7, 5, 11,
|
||||
10, 15, 4, 2, 7, 12, 9, 5, 6, 1, 13, 14, 0, 11, 3, 8,
|
||||
9, 14, 15, 5, 2, 8, 12, 3, 7, 0, 4, 10, 1, 13, 11, 6,
|
||||
4, 3, 2, 12, 9, 5, 15, 10, 11, 14, 1, 7, 6, 0, 8, 13],
|
||||
|
||||
# S7
|
||||
[4, 11, 2, 14, 15, 0, 8, 13, 3, 12, 9, 7, 5, 10, 6, 1,
|
||||
13, 0, 11, 7, 4, 9, 1, 10, 14, 3, 5, 12, 2, 15, 8, 6,
|
||||
1, 4, 11, 13, 12, 3, 7, 14, 10, 15, 6, 8, 0, 5, 9, 2,
|
||||
6, 11, 13, 8, 1, 4, 10, 7, 9, 5, 0, 15, 14, 2, 3, 12],
|
||||
|
||||
# S8
|
||||
[13, 2, 8, 4, 6, 15, 11, 1, 10, 9, 3, 14, 5, 0, 12, 7,
|
||||
1, 15, 13, 8, 10, 3, 7, 4, 12, 5, 6, 11, 0, 14, 9, 2,
|
||||
7, 11, 4, 1, 9, 12, 14, 2, 0, 6, 10, 13, 15, 3, 5, 8,
|
||||
2, 1, 14, 7, 4, 10, 8, 13, 15, 12, 9, 0, 3, 5, 6, 11],
|
||||
]
|
||||
|
||||
|
||||
# 32-bit permutation function P used on the output of the S-boxes
|
||||
__p = [
|
||||
15, 6, 19, 20, 28, 11,
|
||||
27, 16, 0, 14, 22, 25,
|
||||
4, 17, 30, 9, 1, 7,
|
||||
23, 13, 31, 26, 2, 8,
|
||||
18, 12, 29, 5, 21, 10,
|
||||
3, 24
|
||||
]
|
||||
|
||||
# final permutation IP^-1
|
||||
__fp = [
|
||||
39, 7, 47, 15, 55, 23, 63, 31,
|
||||
38, 6, 46, 14, 54, 22, 62, 30,
|
||||
37, 5, 45, 13, 53, 21, 61, 29,
|
||||
36, 4, 44, 12, 52, 20, 60, 28,
|
||||
35, 3, 43, 11, 51, 19, 59, 27,
|
||||
34, 2, 42, 10, 50, 18, 58, 26,
|
||||
33, 1, 41, 9, 49, 17, 57, 25,
|
||||
32, 0, 40, 8, 48, 16, 56, 24
|
||||
]
|
||||
|
||||
# Type of crypting being done
|
||||
ENCRYPT = 0x00
|
||||
DECRYPT = 0x01
|
||||
|
||||
# Initialisation
|
||||
def __init__(self, key, mode=ECB, IV=None, pad=None, padmode=PAD_NORMAL):
|
||||
# Sanity checking of arguments.
|
||||
if len(key) != 8:
|
||||
raise ValueError("Invalid DES key size. Key must be exactly 8 bytes long.")
|
||||
_baseDes.__init__(self, mode, IV, pad, padmode)
|
||||
self.key_size = 8
|
||||
|
||||
self.L = []
|
||||
self.R = []
|
||||
self.Kn = [[0] * 48] * 16 # 16 48-bit keys (K1 - K16)
|
||||
self.final = []
|
||||
|
||||
self.setKey(key)
|
||||
|
||||
def setKey(self, key):
|
||||
"""Will set the crypting key for this object. Must be 8 bytes."""
|
||||
_baseDes.setKey(self, key)
|
||||
self.__create_sub_keys()
|
||||
|
||||
def __String_to_BitList(self, data):
|
||||
"""Turn the string data, into a list of bits (1, 0)'s"""
|
||||
if _pythonMajorVersion < 3:
|
||||
# Turn the strings into integers. Python 3 uses a bytes
|
||||
# class, which already has this behaviour.
|
||||
data = [ord(c) for c in data]
|
||||
l = len(data) * 8
|
||||
result = [0] * l
|
||||
pos = 0
|
||||
for ch in data:
|
||||
i = 7
|
||||
while i >= 0:
|
||||
if ch & (1 << i) != 0:
|
||||
result[pos] = 1
|
||||
else:
|
||||
result[pos] = 0
|
||||
pos += 1
|
||||
i -= 1
|
||||
|
||||
return result
|
||||
|
||||
def __BitList_to_String(self, data):
|
||||
"""Turn the list of bits -> data, into a string"""
|
||||
result = []
|
||||
pos = 0
|
||||
c = 0
|
||||
while pos < len(data):
|
||||
c += data[pos] << (7 - (pos % 8))
|
||||
if (pos % 8) == 7:
|
||||
result.append(c)
|
||||
c = 0
|
||||
pos += 1
|
||||
|
||||
if _pythonMajorVersion < 3:
|
||||
return ''.join([chr(c) for c in result])
|
||||
else:
|
||||
return bytes(result)
|
||||
|
||||
def __permutate(self, table, block):
|
||||
"""Permutate this block with the specified table"""
|
||||
return list(map(lambda x: block[x], table))
|
||||
|
||||
# Transform the secret key, so that it is ready for data processing
|
||||
# Create the 16 subkeys, K[1] - K[16]
|
||||
def __create_sub_keys(self):
|
||||
"""Create the 16 subkeys K[1] to K[16] from the given key"""
|
||||
key = self.__permutate(des.__pc1, self.__String_to_BitList(self.getKey()))
|
||||
i = 0
|
||||
# Split into Left and Right sections
|
||||
self.L = key[:28]
|
||||
self.R = key[28:]
|
||||
while i < 16:
|
||||
j = 0
|
||||
# Perform circular left shifts
|
||||
while j < des.__left_rotations[i]:
|
||||
self.L.append(self.L[0])
|
||||
del self.L[0]
|
||||
|
||||
self.R.append(self.R[0])
|
||||
del self.R[0]
|
||||
|
||||
j += 1
|
||||
|
||||
# Create one of the 16 subkeys through pc2 permutation
|
||||
self.Kn[i] = self.__permutate(des.__pc2, self.L + self.R)
|
||||
|
||||
i += 1
|
||||
|
||||
# Main part of the encryption algorithm, the number cruncher :)
|
||||
def __des_crypt(self, block, crypt_type):
|
||||
"""Crypt the block of data through DES bit-manipulation"""
|
||||
block = self.__permutate(des.__ip, block)
|
||||
self.L = block[:32]
|
||||
self.R = block[32:]
|
||||
|
||||
# Encryption starts from Kn[1] through to Kn[16]
|
||||
if crypt_type == des.ENCRYPT:
|
||||
iteration = 0
|
||||
iteration_adjustment = 1
|
||||
# Decryption starts from Kn[16] down to Kn[1]
|
||||
else:
|
||||
iteration = 15
|
||||
iteration_adjustment = -1
|
||||
|
||||
i = 0
|
||||
while i < 16:
|
||||
# Make a copy of R[i-1], this will later become L[i]
|
||||
tempR = self.R[:]
|
||||
|
||||
# Permutate R[i - 1] to start creating R[i]
|
||||
self.R = self.__permutate(des.__expansion_table, self.R)
|
||||
|
||||
# Exclusive or R[i - 1] with K[i], create B[1] to B[8] whilst here
|
||||
self.R = list(map(lambda x, y: x ^ y, self.R, self.Kn[iteration]))
|
||||
B = [self.R[:6], self.R[6:12], self.R[12:18], self.R[18:24], self.R[24:30], self.R[30:36], self.R[36:42], self.R[42:]]
|
||||
# Optimization: Replaced below commented code with above
|
||||
# j = 0
|
||||
# B = []
|
||||
# while j < len(self.R):
|
||||
# self.R[j] = self.R[j] ^ self.Kn[iteration][j]
|
||||
# j += 1
|
||||
# if j % 6 == 0:
|
||||
# B.append(self.R[j-6:j])
|
||||
|
||||
# Permutate B[1] to B[8] using the S-Boxes
|
||||
j = 0
|
||||
Bn = [0] * 32
|
||||
pos = 0
|
||||
while j < 8:
|
||||
# Work out the offsets
|
||||
m = (B[j][0] << 1) + B[j][5]
|
||||
n = (B[j][1] << 3) + (B[j][2] << 2) + (B[j][3] << 1) + B[j][4]
|
||||
|
||||
# Find the permutation value
|
||||
v = des.__sbox[j][(m << 4) + n]
|
||||
|
||||
# Turn value into bits, add it to result: Bn
|
||||
Bn[pos] = (v & 8) >> 3
|
||||
Bn[pos + 1] = (v & 4) >> 2
|
||||
Bn[pos + 2] = (v & 2) >> 1
|
||||
Bn[pos + 3] = v & 1
|
||||
|
||||
pos += 4
|
||||
j += 1
|
||||
|
||||
# Permutate the concatination of B[1] to B[8] (Bn)
|
||||
self.R = self.__permutate(des.__p, Bn)
|
||||
|
||||
# Xor with L[i - 1]
|
||||
self.R = list(map(lambda x, y: x ^ y, self.R, self.L))
|
||||
# Optimization: This now replaces the below commented code
|
||||
# j = 0
|
||||
# while j < len(self.R):
|
||||
# self.R[j] = self.R[j] ^ self.L[j]
|
||||
# j += 1
|
||||
|
||||
# L[i] becomes R[i - 1]
|
||||
self.L = tempR
|
||||
|
||||
i += 1
|
||||
iteration += iteration_adjustment
|
||||
|
||||
# Final permutation of R[16]L[16]
|
||||
self.final = self.__permutate(des.__fp, self.R + self.L)
|
||||
return self.final
|
||||
|
||||
# Data to be encrypted/decrypted
|
||||
def crypt(self, data, crypt_type):
|
||||
"""Crypt the data in blocks, running it through des_crypt()"""
|
||||
|
||||
# Error check the data
|
||||
if not data:
|
||||
return ''
|
||||
if len(data) % self.block_size != 0:
|
||||
if crypt_type == des.DECRYPT: # Decryption must work on 8 byte blocks
|
||||
raise ValueError("Invalid data length, data must be a multiple of " + str(self.block_size) + " bytes\n.")
|
||||
if not self.getPadding():
|
||||
raise ValueError("Invalid data length, data must be a multiple of " + str(self.block_size) + " bytes\n. Try setting the optional padding character")
|
||||
else:
|
||||
data += (self.block_size - (len(data) % self.block_size)) * self.getPadding()
|
||||
# print "Len of data: %f" % (len(data) / self.block_size)
|
||||
|
||||
if self.getMode() == CBC:
|
||||
if self.getIV():
|
||||
iv = self.__String_to_BitList(self.getIV())
|
||||
else:
|
||||
raise ValueError("For CBC mode, you must supply the Initial Value (IV) for ciphering")
|
||||
|
||||
# Split the data into blocks, crypting each one seperately
|
||||
i = 0
|
||||
dict = {}
|
||||
result = []
|
||||
# cached = 0
|
||||
# lines = 0
|
||||
while i < len(data):
|
||||
# Test code for caching encryption results
|
||||
# lines += 1
|
||||
# if dict.has_key(data[i:i+8]):
|
||||
# print "Cached result for: %s" % data[i:i+8]
|
||||
# cached += 1
|
||||
# result.append(dict[data[i:i+8]])
|
||||
# i += 8
|
||||
# continue
|
||||
|
||||
block = self.__String_to_BitList(data[i:i + 8])
|
||||
|
||||
# Xor with IV if using CBC mode
|
||||
if self.getMode() == CBC:
|
||||
if crypt_type == des.ENCRYPT:
|
||||
block = list(map(lambda x, y: x ^ y, block, iv))
|
||||
# j = 0
|
||||
# while j < len(block):
|
||||
# block[j] = block[j] ^ iv[j]
|
||||
# j += 1
|
||||
|
||||
processed_block = self.__des_crypt(block, crypt_type)
|
||||
|
||||
if crypt_type == des.DECRYPT:
|
||||
processed_block = list(map(lambda x, y: x ^ y, processed_block, iv))
|
||||
# j = 0
|
||||
# while j < len(processed_block):
|
||||
# processed_block[j] = processed_block[j] ^ iv[j]
|
||||
# j += 1
|
||||
iv = block
|
||||
else:
|
||||
iv = processed_block
|
||||
else:
|
||||
processed_block = self.__des_crypt(block, crypt_type)
|
||||
|
||||
|
||||
# Add the resulting crypted block to our list
|
||||
# d = self.__BitList_to_String(processed_block)
|
||||
# result.append(d)
|
||||
result.append(self.__BitList_to_String(processed_block))
|
||||
# dict[data[i:i+8]] = d
|
||||
i += 8
|
||||
|
||||
# print "Lines: %d, cached: %d" % (lines, cached)
|
||||
|
||||
# Return the full crypted string
|
||||
if _pythonMajorVersion < 3:
|
||||
return ''.join(result)
|
||||
else:
|
||||
return bytes.fromhex('').join(result)
|
||||
|
||||
def encrypt(self, data, pad=None, padmode=None):
|
||||
"""encrypt(data, [pad], [padmode]) -> bytes
|
||||
|
||||
data : Bytes to be encrypted
|
||||
pad : Optional argument for encryption padding. Must only be one byte
|
||||
padmode : Optional argument for overriding the padding mode.
|
||||
|
||||
The data must be a multiple of 8 bytes and will be encrypted
|
||||
with the already specified key. Data does not have to be a
|
||||
multiple of 8 bytes if the padding character is supplied, or
|
||||
the padmode is set to PAD_PKCS5, as bytes will then added to
|
||||
ensure the be padded data is a multiple of 8 bytes.
|
||||
"""
|
||||
data = self._guardAgainstUnicode(data)
|
||||
if pad is not None:
|
||||
pad = self._guardAgainstUnicode(pad)
|
||||
data = self._padData(data, pad, padmode)
|
||||
return self.crypt(data, des.ENCRYPT)
|
||||
|
||||
def decrypt(self, data, pad=None, padmode=None):
|
||||
"""decrypt(data, [pad], [padmode]) -> bytes
|
||||
|
||||
data : Bytes to be encrypted
|
||||
pad : Optional argument for decryption padding. Must only be one byte
|
||||
padmode : Optional argument for overriding the padding mode.
|
||||
|
||||
The data must be a multiple of 8 bytes and will be decrypted
|
||||
with the already specified key. In PAD_NORMAL mode, if the
|
||||
optional padding character is supplied, then the un-encrypted
|
||||
data will have the padding characters removed from the end of
|
||||
the bytes. This pad removal only occurs on the last 8 bytes of
|
||||
the data (last data block). In PAD_PKCS5 mode, the special
|
||||
padding end markers will be removed from the data after decrypting.
|
||||
"""
|
||||
data = self._guardAgainstUnicode(data)
|
||||
if pad is not None:
|
||||
pad = self._guardAgainstUnicode(pad)
|
||||
data = self.crypt(data, des.DECRYPT)
|
||||
return self._unpadData(data, pad, padmode)
|
||||
|
||||
|
||||
#############################################################################
|
||||
# Triple DES #
|
||||
#############################################################################
|
||||
class triple_des(_baseDes):
|
||||
"""Triple DES encryption/decrytpion class
|
||||
|
||||
This algorithm uses the DES-EDE3 (when a 24 byte key is supplied) or
|
||||
the DES-EDE2 (when a 16 byte key is supplied) encryption methods.
|
||||
Supports ECB (Electronic Code Book) and CBC (Cypher Block Chaining) modes.
|
||||
|
||||
pyDes.des(key, [mode], [IV])
|
||||
|
||||
key -> Bytes containing the encryption key, must be either 16 or
|
||||
bytes long
|
||||
mode -> Optional argument for encryption type, can be either pyDes.ECB
|
||||
(Electronic Code Book), pyDes.CBC (Cypher Block Chaining)
|
||||
IV -> Optional Initial Value bytes, must be supplied if using CBC mode.
|
||||
Must be 8 bytes in length.
|
||||
pad -> Optional argument, set the pad character (PAD_NORMAL) to use
|
||||
during all encrypt/decrpt operations done with this instance.
|
||||
padmode -> Optional argument, set the padding mode (PAD_NORMAL or
|
||||
PAD_PKCS5) to use during all encrypt/decrpt operations done
|
||||
with this instance.
|
||||
"""
|
||||
|
||||
def __init__(self, key, mode=ECB, IV=None, pad=None, padmode=PAD_NORMAL):
|
||||
_baseDes.__init__(self, mode, IV, pad, padmode)
|
||||
self.setKey(key)
|
||||
|
||||
def setKey(self, key):
|
||||
"""Will set the crypting key for this object. Either 16 or 24 bytes long."""
|
||||
self.key_size = 24 # Use DES-EDE3 mode
|
||||
if len(key) != self.key_size:
|
||||
if len(key) == 16: # Use DES-EDE2 mode
|
||||
self.key_size = 16
|
||||
else:
|
||||
raise ValueError("Invalid triple DES key size. Key must be either 16 or 24 bytes long")
|
||||
if self.getMode() == CBC:
|
||||
if not self.getIV():
|
||||
# Use the first 8 bytes of the key
|
||||
self._iv = key[:self.block_size]
|
||||
if len(self.getIV()) != self.block_size:
|
||||
raise ValueError("Invalid IV, must be 8 bytes in length")
|
||||
self.__key1 = des(key[:8], self._mode, self._iv,
|
||||
self._padding, self._padmode)
|
||||
self.__key2 = des(key[8:16], self._mode, self._iv,
|
||||
self._padding, self._padmode)
|
||||
if self.key_size == 16:
|
||||
self.__key3 = self.__key1
|
||||
else:
|
||||
self.__key3 = des(key[16:], self._mode, self._iv,
|
||||
self._padding, self._padmode)
|
||||
_baseDes.setKey(self, key)
|
||||
|
||||
# Override setter methods to work on all 3 keys.
|
||||
|
||||
def setMode(self, mode):
|
||||
"""Sets the type of crypting mode, pyDes.ECB or pyDes.CBC"""
|
||||
_baseDes.setMode(self, mode)
|
||||
for key in (self.__key1, self.__key2, self.__key3):
|
||||
key.setMode(mode)
|
||||
|
||||
def setPadding(self, pad):
|
||||
"""setPadding() -> bytes of length 1. Padding character."""
|
||||
_baseDes.setPadding(self, pad)
|
||||
for key in (self.__key1, self.__key2, self.__key3):
|
||||
key.setPadding(pad)
|
||||
|
||||
def setPadMode(self, mode):
|
||||
"""Sets the type of padding mode, pyDes.PAD_NORMAL or pyDes.PAD_PKCS5"""
|
||||
_baseDes.setPadMode(self, mode)
|
||||
for key in (self.__key1, self.__key2, self.__key3):
|
||||
key.setPadMode(mode)
|
||||
|
||||
def setIV(self, IV):
|
||||
"""Will set the Initial Value, used in conjunction with CBC mode"""
|
||||
_baseDes.setIV(self, IV)
|
||||
for key in (self.__key1, self.__key2, self.__key3):
|
||||
key.setIV(IV)
|
||||
|
||||
def encrypt(self, data, pad=None, padmode=None):
|
||||
"""encrypt(data, [pad], [padmode]) -> bytes
|
||||
|
||||
data : bytes to be encrypted
|
||||
pad : Optional argument for encryption padding. Must only be one byte
|
||||
padmode : Optional argument for overriding the padding mode.
|
||||
|
||||
The data must be a multiple of 8 bytes and will be encrypted
|
||||
with the already specified key. Data does not have to be a
|
||||
multiple of 8 bytes if the padding character is supplied, or
|
||||
the padmode is set to PAD_PKCS5, as bytes will then added to
|
||||
ensure the be padded data is a multiple of 8 bytes.
|
||||
"""
|
||||
ENCRYPT = des.ENCRYPT
|
||||
DECRYPT = des.DECRYPT
|
||||
data = self._guardAgainstUnicode(data)
|
||||
if pad is not None:
|
||||
pad = self._guardAgainstUnicode(pad)
|
||||
# Pad the data accordingly.
|
||||
data = self._padData(data, pad, padmode)
|
||||
if self.getMode() == CBC:
|
||||
self.__key1.setIV(self.getIV())
|
||||
self.__key2.setIV(self.getIV())
|
||||
self.__key3.setIV(self.getIV())
|
||||
i = 0
|
||||
result = []
|
||||
while i < len(data):
|
||||
block = self.__key1.crypt(data[i:i + 8], ENCRYPT)
|
||||
block = self.__key2.crypt(block, DECRYPT)
|
||||
block = self.__key3.crypt(block, ENCRYPT)
|
||||
self.__key1.setIV(block)
|
||||
self.__key2.setIV(block)
|
||||
self.__key3.setIV(block)
|
||||
result.append(block)
|
||||
i += 8
|
||||
if _pythonMajorVersion < 3:
|
||||
return ''.join(result)
|
||||
else:
|
||||
return bytes.fromhex('').join(result)
|
||||
else:
|
||||
data = self.__key1.crypt(data, ENCRYPT)
|
||||
data = self.__key2.crypt(data, DECRYPT)
|
||||
return self.__key3.crypt(data, ENCRYPT)
|
||||
|
||||
def decrypt(self, data, pad=None, padmode=None):
|
||||
"""decrypt(data, [pad], [padmode]) -> bytes
|
||||
|
||||
data : bytes to be encrypted
|
||||
pad : Optional argument for decryption padding. Must only be one byte
|
||||
padmode : Optional argument for overriding the padding mode.
|
||||
|
||||
The data must be a multiple of 8 bytes and will be decrypted
|
||||
with the already specified key. In PAD_NORMAL mode, if the
|
||||
optional padding character is supplied, then the un-encrypted
|
||||
data will have the padding characters removed from the end of
|
||||
the bytes. This pad removal only occurs on the last 8 bytes of
|
||||
the data (last data block). In PAD_PKCS5 mode, the special
|
||||
padding end markers will be removed from the data after
|
||||
decrypting, no pad character is required for PAD_PKCS5.
|
||||
"""
|
||||
ENCRYPT = des.ENCRYPT
|
||||
DECRYPT = des.DECRYPT
|
||||
data = self._guardAgainstUnicode(data)
|
||||
if pad is not None:
|
||||
pad = self._guardAgainstUnicode(pad)
|
||||
if self.getMode() == CBC:
|
||||
self.__key1.setIV(self.getIV())
|
||||
self.__key2.setIV(self.getIV())
|
||||
self.__key3.setIV(self.getIV())
|
||||
i = 0
|
||||
result = []
|
||||
while i < len(data):
|
||||
iv = data[i:i + 8]
|
||||
block = self.__key3.crypt(iv, DECRYPT)
|
||||
block = self.__key2.crypt(block, ENCRYPT)
|
||||
block = self.__key1.crypt(block, DECRYPT)
|
||||
self.__key1.setIV(iv)
|
||||
self.__key2.setIV(iv)
|
||||
self.__key3.setIV(iv)
|
||||
result.append(block)
|
||||
i += 8
|
||||
if _pythonMajorVersion < 3:
|
||||
data = ''.join(result)
|
||||
else:
|
||||
data = bytes.fromhex('').join(result)
|
||||
else:
|
||||
data = self.__key3.crypt(data, DECRYPT)
|
||||
data = self.__key2.crypt(data, ENCRYPT)
|
||||
data = self.__key1.crypt(data, DECRYPT)
|
||||
return self._unpadData(data, pad, padmode)
|
|
@ -1,19 +1,26 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
# 检测运行环境和相对定位文件路径
|
||||
"""
|
||||
检测运行环境和相对定位文件路径
|
||||
目录结构说明:
|
||||
PATH_APP_ROOT
|
||||
|- app
|
||||
|- res
|
||||
|- static
|
||||
\- view
|
||||
"""
|
||||
|
||||
import os
|
||||
import platform
|
||||
import sys
|
||||
|
||||
__all__ = ['PATH_APP_ROOT', 'PATH_LOG', 'PATH_CONF', 'PATH_DATA', 'DEV_MODE']
|
||||
__all__ = ['PATH_APP_ROOT', 'PATH_LOG', 'PATH_CONF', 'PATH_DATA']
|
||||
|
||||
PATH_LOG = ''
|
||||
PATH_CONF = ''
|
||||
PATH_DATA = ''
|
||||
DEV_MODE = False
|
||||
|
||||
# 将Python安装的扩展库移除,避免开发调试与正式发布所依赖的库文件不一致导致发布出去的版本无法运行
|
||||
# 将Python安装的扩展库移除,避免开发调试与正式发布所依赖的库文件不一致导致发布的版本无法运行
|
||||
x = []
|
||||
for p in sys.path:
|
||||
if p.find('site-packages') != -1 or p.find('dist-packages') != -1:
|
||||
|
@ -21,51 +28,64 @@ for p in sys.path:
|
|||
for p in x:
|
||||
sys.path.remove(p)
|
||||
|
||||
is_dev_mode = False
|
||||
path_of_this_file = os.path.abspath(os.path.dirname(__file__))
|
||||
|
||||
PATH_APP_ROOT = os.path.abspath(os.path.join(path_of_this_file, '..'))
|
||||
|
||||
# 根据源代码目录形式,检查是否是开发版本
|
||||
if os.path.exists(os.path.join(PATH_APP_ROOT, '..', '..', 'share', 'etc')):
|
||||
is_dev_mode = True
|
||||
|
||||
# 检查操作系统,目前仅支持Win和Linux
|
||||
PLATFORM = platform.system().lower()
|
||||
if PLATFORM not in ['windows', 'linux']:
|
||||
print('Teleport WEB Server support Windows and Linux only.')
|
||||
sys.exit(1)
|
||||
|
||||
BITS = 'x64'
|
||||
if '32bit' == platform.architecture()[0]:
|
||||
BITS = 'x86'
|
||||
|
||||
path_of_this_file = os.path.abspath(os.path.dirname(__file__))
|
||||
PATH_APP_ROOT = os.path.abspath(os.path.join(path_of_this_file, '..'))
|
||||
# 引入必要的扩展库
|
||||
_ext_path = os.path.abspath(os.path.join(PATH_APP_ROOT, '..', 'packages', 'packages-common'))
|
||||
if _ext_path not in sys.path:
|
||||
sys.path.append(_ext_path)
|
||||
|
||||
# 如果没有打包,可能是开发版本,也可能是发布源代码版本,需要进一步判断
|
||||
if os.path.exists(os.path.join(PATH_APP_ROOT, '..', '..', 'share', 'etc')):
|
||||
DEV_MODE = True
|
||||
elif os.path.exists(os.path.join(PATH_APP_ROOT, '..', '..', 'etc')):
|
||||
DEV_MODE = False
|
||||
else:
|
||||
print('invalid installation.\n')
|
||||
sys.exit(1)
|
||||
_ext_path = os.path.abspath(os.path.join(PATH_APP_ROOT, '..', 'packages', 'packages-{}'.format(PLATFORM), BITS))
|
||||
if _ext_path not in sys.path:
|
||||
sys.path.append(_ext_path)
|
||||
|
||||
|
||||
if DEV_MODE:
|
||||
# 确定一些路径
|
||||
if is_dev_mode:
|
||||
# 开发调试模式
|
||||
_ext_path = os.path.abspath(os.path.join(PATH_APP_ROOT, '..', 'packages', 'packages-common'))
|
||||
if _ext_path not in sys.path:
|
||||
sys.path.append(_ext_path)
|
||||
|
||||
_ext_path = os.path.abspath(
|
||||
os.path.join(PATH_APP_ROOT, '..', 'packages', 'packages-{}'.format(PLATFORM), BITS))
|
||||
if _ext_path not in sys.path:
|
||||
sys.path.append(_ext_path)
|
||||
|
||||
# _ext_path = os.path.abspath(os.path.join(PATH_APP_ROOT, '..', 'packages', 'packages-common'))
|
||||
# if _ext_path not in sys.path:
|
||||
# sys.path.append(_ext_path)
|
||||
#
|
||||
# _ext_path = os.path.abspath(os.path.join(PATH_APP_ROOT, '..', 'packages', 'packages-{}'.format(PLATFORM), BITS))
|
||||
# if _ext_path not in sys.path:
|
||||
# sys.path.append(_ext_path)
|
||||
#
|
||||
PATH_LOG = os.path.abspath(os.path.join(PATH_APP_ROOT, '..', '..', 'share', 'log'))
|
||||
PATH_CONF = os.path.abspath(os.path.join(PATH_APP_ROOT, '..', '..', 'share', 'etc'))
|
||||
PATH_DATA = os.path.abspath(os.path.join(PATH_APP_ROOT, '..', '..', 'share', 'data'))
|
||||
|
||||
else:
|
||||
_ext_path = os.path.abspath(os.path.join(PATH_APP_ROOT, '..', 'packages', 'packages-common'))
|
||||
if _ext_path not in sys.path:
|
||||
sys.path.append(_ext_path)
|
||||
|
||||
_ext_path = os.path.abspath(os.path.join(PATH_APP_ROOT, '..', 'packages', 'packages-{}'.format(PLATFORM), BITS))
|
||||
if _ext_path not in sys.path:
|
||||
sys.path.append(_ext_path)
|
||||
|
||||
# _ext_path = os.path.abspath(os.path.join(PATH_APP_ROOT, '..', 'packages', 'packages-common'))
|
||||
# if _ext_path not in sys.path:
|
||||
# sys.path.append(_ext_path)
|
||||
#
|
||||
# _ext_path = os.path.abspath(os.path.join(PATH_APP_ROOT, '..', 'packages', 'packages-{}'.format(PLATFORM), BITS))
|
||||
# if _ext_path not in sys.path:
|
||||
# sys.path.append(_ext_path)
|
||||
#
|
||||
PATH_LOG = os.path.abspath(os.path.join(PATH_APP_ROOT, '..', '..', 'log'))
|
||||
PATH_CONF = os.path.abspath(os.path.join(PATH_APP_ROOT, '..', '..', 'etc'))
|
||||
PATH_DATA = os.path.abspath(os.path.join(PATH_APP_ROOT, '..', '..', 'data'))
|
||||
|
||||
if PLATFORM == 'linux':
|
||||
# 根据Linux目录规范建议设置各个必要的路径
|
||||
PATH_LOG = '/var/log/teleport'
|
||||
PATH_CONF = '/etc/teleport'
|
||||
PATH_DATA = '/var/lib/teleport'
|
||||
|
|
|
@ -4,35 +4,30 @@ import os
|
|||
import sys
|
||||
from eom_env import *
|
||||
import eom_app.app as app
|
||||
# from eom_common.eomcore.logger import *
|
||||
|
||||
# log.set_attribute(min_level=LOG_INFO, trace_error=TRACE_ERROR_NONE)
|
||||
|
||||
|
||||
def main():
|
||||
options = {
|
||||
# app_path 网站程序代码路径,用于内部合成controller和model的路径,必须指定
|
||||
# app_path 网站程序根路径(应该是本文件所在目录的上一级目录)
|
||||
'app_path': PATH_APP_ROOT,
|
||||
|
||||
# cfg_path 网站配置文件路径,如未指定,默认为 $_root_path$/conf
|
||||
# cfg_path 网站配置文件路径
|
||||
'cfg_path': PATH_CONF,
|
||||
|
||||
# log_path 网站运行时日志文件路径,如未指定,默认为 $_root_path$/log
|
||||
# log_path 网站运行时日志文件路径
|
||||
'log_path': PATH_LOG,
|
||||
|
||||
# static_path 网站静态文件路径,如未指定,默认为 $_root_path$/static
|
||||
# static_path 网站静态文件路径
|
||||
'static_path': os.path.join(PATH_APP_ROOT, 'static'),
|
||||
|
||||
# data_path 网站数据文件路径,如未指定,默认为 $_root_path$/data
|
||||
# data_path 网站数据文件路径
|
||||
'data_path': PATH_DATA,
|
||||
|
||||
# template_path 网站模板文件路径,如未指定,默认为 $_root_path$/template
|
||||
# template_path 网站模板文件路径
|
||||
'template_path': os.path.join(PATH_APP_ROOT, 'view'),
|
||||
|
||||
# res_path 网站资源文件路径,例如字体文件等,默认为 $_root_path$/res
|
||||
'res_path': os.path.join(PATH_APP_ROOT, 'res'),
|
||||
|
||||
'dev_mode': DEV_MODE,
|
||||
# res_path 网站资源文件路径
|
||||
'res_path': os.path.join(PATH_APP_ROOT, 'res')
|
||||
}
|
||||
|
||||
return app.run(options)
|
||||
|
|
|
@ -575,7 +575,7 @@ ywl.on_host_table_created = function (tbl) {
|
|||
// ret.push('<a href="javascript:;" class="btn btn-sm btn-primary" ywl-btn-remote="' + fields.id + '"><i class="fa fa-desktop fa-fw"></i> 远程</a>');
|
||||
ret.push('</div>');
|
||||
return ret.join('');
|
||||
}
|
||||
};
|
||||
render.make_user_btn = function (row_id, fields) {
|
||||
var ret = [];
|
||||
ret.push('<div class="btn-group btn-group-sm" role="group">');
|
||||
|
@ -866,7 +866,6 @@ ywl.create_host_edit_dlg = function (tbl) {
|
|||
return dlg_edit_host;
|
||||
};
|
||||
|
||||
|
||||
ywl.create_host_user_edit_dlg = function (tbl) {
|
||||
var dlg_user_edit_host = {};
|
||||
dlg_user_edit_host.dom_id = "#dialog-host-user-edit";
|
||||
|
@ -1025,7 +1024,6 @@ ywl.create_host_user_edit_dlg = function (tbl) {
|
|||
return dlg_user_edit_host;
|
||||
};
|
||||
|
||||
|
||||
ywl.create_sys_user = function (tbl) {
|
||||
|
||||
var dlg_sys_user = {};
|
||||
|
@ -1433,6 +1431,7 @@ ywl.create_sys_user = function (tbl) {
|
|||
return dlg_sys_user;
|
||||
|
||||
};
|
||||
|
||||
ywl.create_batch_join_group_dlg = function (tbl) {
|
||||
var batch_join_dlg = {};
|
||||
|
||||
|
|
|
@ -113,11 +113,11 @@ var to_teleport = function (url, args, func_success, func_error) {
|
|||
}
|
||||
});
|
||||
} else {
|
||||
func_error(TP_ERR_CORE_SRV, 'Web:远程连接请求失败,可能teleport核心服务尚未启动!');
|
||||
func_error(TP_ERR_CORE_SRV, '远程连接请求失败,可能teleport核心服务尚未启动!');
|
||||
}
|
||||
},
|
||||
error: function () {
|
||||
func_error(TP_ERR_NETWORK, 'Web:远程网络通讯失败!');
|
||||
func_error(TP_ERR_NETWORK, '远程网络通讯失败!');
|
||||
}
|
||||
});
|
||||
};
|
||||
|
@ -162,11 +162,11 @@ var to_admin_teleport = function (url, args, func_success, func_error) {
|
|||
}
|
||||
});
|
||||
} else {
|
||||
func_error(TP_ERR_CORE_SRV, 'Web:远程连接请求失败,可能teleport核心服务尚未启动!');
|
||||
func_error(TP_ERR_CORE_SRV, '远程连接请求失败,可能teleport核心服务尚未启动!');
|
||||
}
|
||||
},
|
||||
error: function () {
|
||||
func_error(TP_ERR_NETWORK, 'Web:远程网络通讯失败!');
|
||||
func_error(TP_ERR_NETWORK, '远程网络通讯失败!');
|
||||
}
|
||||
});
|
||||
};
|
||||
|
@ -214,11 +214,11 @@ var to_admin_fast_teleport = function (url, args, func_success, func_error) {
|
|||
}
|
||||
});
|
||||
} else {
|
||||
func_error(TP_ERR_CORE_SRV, 'Web:远程连接请求失败,可能teleport核心服务尚未启动!');
|
||||
func_error(TP_ERR_CORE_SRV, '远程连接请求失败,可能teleport核心服务尚未启动!');
|
||||
}
|
||||
},
|
||||
error: function () {
|
||||
func_error(TP_ERR_NETWORK, 'Web:远程网络通讯失败!');
|
||||
func_error(TP_ERR_NETWORK, '远程网络通讯失败!');
|
||||
}
|
||||
});
|
||||
};
|
||||
|
@ -241,7 +241,7 @@ var start_rdp_replay = function (args, func_success, func_error) {
|
|||
console.log('ret', ret);
|
||||
},
|
||||
error: function () {
|
||||
func_error(TP_ERR_NETWORK, 'Web:远程网络通讯失败!');
|
||||
func_error(TP_ERR_NETWORK, '远程网络通讯失败!');
|
||||
}
|
||||
});
|
||||
};
|
||||
|
|
|
@ -0,0 +1,69 @@
|
|||
<%!
|
||||
page_title_ = '系统维护'
|
||||
## page_menu_ = ['user']
|
||||
## page_id_ = 'user'
|
||||
%>
|
||||
<%inherit file="../page_maintenance_base.mako"/>
|
||||
|
||||
<%block name="breadcrumb">
|
||||
<ol class="breadcrumb">
|
||||
<li><i class="fa fa-cog fa-fw"></i> ${self.attr.page_title_}</li>
|
||||
</ol>
|
||||
</%block>
|
||||
|
||||
<%block name="embed_css">
|
||||
<style type="text/css">
|
||||
.content_box {
|
||||
margin-top:48px;
|
||||
}
|
||||
|
||||
.content_box .error_sidebar {
|
||||
float: left;
|
||||
width: 160px;
|
||||
margin-left: 120px;
|
||||
font-size: 260px;
|
||||
color: #e3693b;
|
||||
}
|
||||
|
||||
.content_box .error_content {
|
||||
min-height: 400px;
|
||||
width: 800px;
|
||||
padding: 30px;
|
||||
margin-left: 300px;
|
||||
background: #ffffff;
|
||||
border-radius: 5px;
|
||||
|
||||
background: rgba(255, 255, 255, 0.8);
|
||||
background: #fff \9;
|
||||
z-index: 9;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
h1 .fa-spin {
|
||||
color:#aaa;
|
||||
}
|
||||
</style>
|
||||
</%block>
|
||||
|
||||
## Begin Main Body.
|
||||
|
||||
<div class="page-content">
|
||||
|
||||
<div class="content_box">
|
||||
<div class="container">
|
||||
|
||||
<div class="error_sidebar">
|
||||
<i class="fa fa-exclamation-triangle"></i>
|
||||
</div>
|
||||
|
||||
<div class="error_content">
|
||||
<br/>
|
||||
<h1><i class="fa fa-cog fa-spin"></i> 系统维护中...</h1>
|
||||
<hr/>
|
||||
<p>系统管理员正在紧张地维护系统,请稍后刷新页面重试!</p>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
|
@ -0,0 +1,104 @@
|
|||
<!DOCTYPE html>
|
||||
<%!
|
||||
page_title_ = ''
|
||||
%>
|
||||
<!--[if IE 8]><html lang="en" class="ie8"> <![endif]-->
|
||||
<!--[if !IE]><!-->
|
||||
<html lang="zh_CN">
|
||||
<!--<![endif]-->
|
||||
<head>
|
||||
<meta charset="utf-8"/>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
|
||||
<meta content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" name="viewport"/>
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge"/>
|
||||
<meta content="yes" name="apple-mobile-web-app-capable">
|
||||
<meta content="black-translucent" name="apple-mobile-web-app-status-bar-style">
|
||||
<title>${self.attr.page_title_}::TELEPORT</title>
|
||||
<link rel="shortcut icon" href="${ static_url('favicon.png') }">
|
||||
|
||||
<link href="${ static_url('plugins/google-cache/open-sans.css') }" rel="stylesheet">
|
||||
<link href="${ static_url('plugins/bootstrap/css/bootstrap.min.css') }" rel="stylesheet" type="text/css"/>
|
||||
<link href="${ static_url('plugins/font-awesome/css/font-awesome.min.css') }" rel="stylesheet">
|
||||
<link href="${ static_url('plugins/gritter/css/jquery.gritter.css') }" rel="stylesheet">
|
||||
|
||||
<link href="${ static_url('css/sub.css') }" rel="stylesheet" type="text/css"/>
|
||||
|
||||
<%block name="extend_css"/>
|
||||
<%block name="embed_css"/>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<!-- begin #page-container -->
|
||||
<div id="page-container" class="page-header-fixed">
|
||||
<div id="header" class="header header-fixed-top">
|
||||
|
||||
<div class="container-fluid top-navbar">
|
||||
<div class="brand"><div class="site-logo"></div></div>
|
||||
<div class="breadcrumb-container">
|
||||
<%block name="breadcrumb" />
|
||||
</div>
|
||||
|
||||
## <div class="status-container">
|
||||
## more status or global tool buttons goes here.
|
||||
## </div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div id="footer" class="footer footer-fixed-bottom">
|
||||
<div class="container">
|
||||
<p>触维软件旗下产品 | TELEPORT | ©2015 - 2017 <a href="http://www.eomsoft.net/" target="_blank">触维软件</a>,保留所有权利。</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="container-fluid">
|
||||
${self.body()}
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<%block name="extend_content" />
|
||||
|
||||
<script type="text/javascript" src="${ static_url('plugins/underscore/underscore.js') }"></script>
|
||||
<script type="text/javascript" src="${ static_url('plugins/jquery/jquery.min.js') }"></script>
|
||||
<script type="text/javascript" src="${ static_url('plugins/bootstrap/js/bootstrap.min.js') }"></script>
|
||||
<!--[if lt IE 9]>
|
||||
<script src="${ static_url('plugins/html5shiv/html5shiv.min.js') }"></script>
|
||||
<![endif]-->
|
||||
## <script type="text/javascript" src="${ static_url('js/json2.js') }"></script>
|
||||
|
||||
<script type="text/javascript" src="${ static_url('plugins/gritter/js/jquery.gritter.js') }"></script>
|
||||
<script type="text/javascript" src="${ static_url('plugins/jstree/jstree.js') }"></script>
|
||||
|
||||
<script type="text/javascript" src="${ static_url('plugins/keypress/keypress.js') }"></script>
|
||||
|
||||
## <script type="text/javascript" src="${ static_url('js/ywl_const.js') }"></script>
|
||||
## <script type="text/javascript" src="${ static_url('js/ywl_common.js') }"></script>
|
||||
## <script type="text/javascript" src="${ static_url('js/ywl.js') }"></script>
|
||||
## <script type="text/javascript" src="${ static_url('js/ywl_assist.js') }"></script>
|
||||
## <script type="text/javascript" src="${ static_url('js/ui/common.js') }"></script>
|
||||
## <script type="text/javascript" src="${ static_url('js/ui/controls.js') }"></script>
|
||||
|
||||
|
||||
<%block name="extend_js"/>
|
||||
|
||||
|
||||
|
||||
<script type="text/javascript">
|
||||
|
||||
$(document).ready(function () {
|
||||
// once page ready, init ywl object.
|
||||
## ywl.init();
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
<%block name="embed_js" />
|
||||
|
||||
|
||||
</body>
|
||||
</html>
|
|
@ -48,7 +48,7 @@
|
|||
|
||||
<div id="footer" class="footer footer-fixed-bottom">
|
||||
<div class="container">
|
||||
<p>触维软件旗下产品 | TELEPORT | ©2015 - 2016 <a href="http://www.eomsoft.net/" target="_blank">触维软件</a>,保留所有权利。</p>
|
||||
<p>触维软件旗下产品 | TELEPORT | ©2015 - 2017 <a href="http://teleport.eomsoft.net/" target="_blank">触维软件</a>,保留所有权利。</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
Loading…
Reference in New Issue