mirror of https://github.com/tp4a/teleport
working...
parent
f142793394
commit
054deb839e
|
@ -0,0 +1,2 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
|
@ -0,0 +1,30 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
from eom_common.eomcore.logger import log
|
||||||
|
from eom_app.app.util import sec_generate_password
|
||||||
|
|
||||||
|
# 升级数据表结构时必须升级此版本号,并编写响应的升级SQL
|
||||||
|
TELEPORT_DATABASE_VERSION = 10
|
||||||
|
|
||||||
|
|
||||||
|
def create_and_init(db, step_begin, step_end):
|
||||||
|
_admin_sec_password = sec_generate_password('admin')
|
||||||
|
|
||||||
|
_step = step_begin('创建表 account')
|
||||||
|
|
||||||
|
ret = db.exec("""CREATE TABLE `{}account` (
|
||||||
|
`account_id` integer PRIMARY KEY AUTOINCREMENT,
|
||||||
|
`account_type` int(11) DEFAULT 0,
|
||||||
|
`account_name` varchar(32) DEFAULT NULL,
|
||||||
|
`account_pwd` varchar(32) DEFAULT NULL,
|
||||||
|
`account_status` int(11) DEFAULT 0,
|
||||||
|
`account_lock` int(11) DEFAULT 0,
|
||||||
|
`account_desc` varchar(255)
|
||||||
|
);""".format(db.table_prefix))
|
||||||
|
if not ret:
|
||||||
|
log.e('create table `account` failed.')
|
||||||
|
step_end(_step, -1)
|
||||||
|
return
|
||||||
|
else:
|
||||||
|
log.i('create table `account` ok.')
|
||||||
|
step_end(_step, 0)
|
|
@ -1,19 +1,20 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
import os
|
|
||||||
import threading
|
|
||||||
import sqlite3
|
|
||||||
import builtins
|
import builtins
|
||||||
|
import os
|
||||||
|
import sqlite3
|
||||||
|
import threading
|
||||||
|
|
||||||
from .configs import app_cfg
|
|
||||||
from eom_common.eomcore.logger import log
|
from eom_common.eomcore.logger import log
|
||||||
|
from .configs import app_cfg
|
||||||
|
from .database.create import create_and_init, TELEPORT_DATABASE_VERSION
|
||||||
|
|
||||||
cfg = app_cfg()
|
cfg = app_cfg()
|
||||||
|
|
||||||
__all__ = ['get_db']
|
__all__ = ['get_db']
|
||||||
|
|
||||||
# 注意,每次调整数据库结构,必须增加版本号,并且在升级接口中编写对应的升级操作
|
# 注意,每次调整数据库结构,必须增加版本号,并且在升级接口中编写对应的升级操作
|
||||||
TELEPORT_DATABASE_VERSION = 2
|
# TELEPORT_DATABASE_VERSION = 2
|
||||||
|
|
||||||
|
|
||||||
class TPDatabase:
|
class TPDatabase:
|
||||||
|
@ -21,15 +22,22 @@ class TPDatabase:
|
||||||
if '__teleport_db__' in builtins.__dict__:
|
if '__teleport_db__' in builtins.__dict__:
|
||||||
raise RuntimeError('TPDatabase object exists, you can not create more than one instance.')
|
raise RuntimeError('TPDatabase object exists, you can not create more than one instance.')
|
||||||
|
|
||||||
|
self._table_prefix = ''
|
||||||
|
|
||||||
self.need_create = False # 数据尚未存在,需要创建
|
self.need_create = False # 数据尚未存在,需要创建
|
||||||
self.need_upgrade = False # 数据库已存在但版本较低,需要升级
|
self.need_upgrade = False # 数据库已存在但版本较低,需要升级
|
||||||
self._conn_pool = None
|
self._conn_pool = None
|
||||||
|
|
||||||
|
@property
|
||||||
|
def table_prefix(self):
|
||||||
|
return self._table_prefix
|
||||||
|
|
||||||
def init_mysql(self):
|
def init_mysql(self):
|
||||||
# NOT SUPPORTED YET
|
# NOT SUPPORTED YET
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def init_sqlite(self, db_file):
|
def init_sqlite(self, db_file):
|
||||||
|
self._table_prefix = 'ts_'
|
||||||
self._conn_pool = TPSqlitePool(db_file)
|
self._conn_pool = TPSqlitePool(db_file)
|
||||||
|
|
||||||
if not os.path.exists(db_file):
|
if not os.path.exists(db_file):
|
||||||
|
@ -38,18 +46,29 @@ class TPDatabase:
|
||||||
return
|
return
|
||||||
|
|
||||||
# 看看数据库中是否存在用户表(如果不存在,可能是一个空数据库文件),则可能是一个新安装的系统
|
# 看看数据库中是否存在用户表(如果不存在,可能是一个空数据库文件),则可能是一个新安装的系统
|
||||||
ret = self._conn_pool.query('SELECT COUNT(*) FROM sqlite_master where type="table" and name="ts_account";')
|
ret = self.query('SELECT COUNT(*) FROM sqlite_master where type="table" and name="ts_account";')
|
||||||
if ret[0][0] == 0:
|
if ret[0][0] == 0:
|
||||||
log.w('database need create.\n')
|
log.w('database need create.\n')
|
||||||
self.need_create = True
|
self.need_create = True
|
||||||
return
|
return
|
||||||
|
|
||||||
# 尝试从配置表中读取当前数据库版本号(如果不存在,说明是比较旧的版本了,则置为0)
|
# 尝试从配置表中读取当前数据库版本号(如果不存在,说明是比较旧的版本了,则置为0)
|
||||||
ret = self._conn_pool.query('SELECT value FROM ts_config where name="db_ver";')
|
ret = self.query('SELECT value FROM ts_config where name="db_ver";')
|
||||||
if 0 == len(ret):
|
if 0 == len(ret):
|
||||||
log.w('database need upgrade.\n')
|
log.w('database need upgrade.\n')
|
||||||
self.need_upgrade = True
|
self.need_upgrade = True
|
||||||
|
|
||||||
|
def query(self, sql):
|
||||||
|
return self._conn_pool.query(sql)
|
||||||
|
|
||||||
|
def exec(self, sql):
|
||||||
|
return self._conn_pool.exec(sql)
|
||||||
|
|
||||||
|
|
||||||
|
def create_and_init(self, step_begin, step_end):
|
||||||
|
step_begin('准备创建数据表')
|
||||||
|
create_and_init(self, step_begin, step_end)
|
||||||
|
|
||||||
|
|
||||||
class TPDatabasePool:
|
class TPDatabasePool:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
|
@ -59,9 +78,15 @@ class TPDatabasePool:
|
||||||
def query(self, sql):
|
def query(self, sql):
|
||||||
_conn = self._get_connect()
|
_conn = self._get_connect()
|
||||||
if _conn is None:
|
if _conn is None:
|
||||||
return list()
|
return None
|
||||||
return self._do_query(_conn, sql)
|
return self._do_query(_conn, sql)
|
||||||
|
|
||||||
|
def exec(self, sql):
|
||||||
|
_conn = self._get_connect()
|
||||||
|
if _conn is None:
|
||||||
|
return False
|
||||||
|
return self._do_exec(_conn, sql)
|
||||||
|
|
||||||
def _get_connect(self):
|
def _get_connect(self):
|
||||||
with self._locker:
|
with self._locker:
|
||||||
thread_id = threading.get_ident()
|
thread_id = threading.get_ident()
|
||||||
|
@ -77,7 +102,10 @@ class TPDatabasePool:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def _do_query(self, conn, sql):
|
def _do_query(self, conn, sql):
|
||||||
return list()
|
return None
|
||||||
|
|
||||||
|
def _do_exec(self, conn, sql):
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
class TPSqlitePool(TPDatabasePool):
|
class TPSqlitePool(TPDatabasePool):
|
||||||
|
@ -99,7 +127,18 @@ class TPSqlitePool(TPDatabasePool):
|
||||||
db_ret = cursor.fetchall()
|
db_ret = cursor.fetchall()
|
||||||
return db_ret
|
return db_ret
|
||||||
except sqlite3.OperationalError:
|
except sqlite3.OperationalError:
|
||||||
return list()
|
return None
|
||||||
|
finally:
|
||||||
|
cursor.close()
|
||||||
|
|
||||||
|
def _do_exec(self, conn, sql):
|
||||||
|
cursor = conn.cursor()
|
||||||
|
try:
|
||||||
|
cursor.execute(sql)
|
||||||
|
conn.commit()
|
||||||
|
return True
|
||||||
|
except sqlite3.OperationalError:
|
||||||
|
return False
|
||||||
finally:
|
finally:
|
||||||
cursor.close()
|
cursor.close()
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
import os
|
import os
|
||||||
import random
|
import random
|
||||||
import io
|
import io
|
||||||
|
import hashlib
|
||||||
|
|
||||||
import json
|
import json
|
||||||
import urllib.parse
|
import urllib.parse
|
||||||
|
@ -23,7 +24,7 @@ from .configs import app_cfg
|
||||||
|
|
||||||
cfg = app_cfg()
|
cfg = app_cfg()
|
||||||
|
|
||||||
__all__ = ['async_post_http', 'async_enc']
|
__all__ = ['async_post_http', 'async_enc', 'gen_captcha', 'sec_generate_password', 'sec_verify_password']
|
||||||
|
|
||||||
|
|
||||||
@tornado.gen.coroutine
|
@tornado.gen.coroutine
|
||||||
|
@ -67,8 +68,8 @@ def async_enc(data):
|
||||||
return {'code': 0, 'data': return_data['data']['c']}
|
return {'code': 0, 'data': return_data['data']['c']}
|
||||||
|
|
||||||
|
|
||||||
_chars = 'AaCDdEeFfHJjKkLMmNnPpQRrTtVvWwXxYy34679'
|
_captcha_chars = 'AaCDdEeFfHJjKkLMmNnPpQRTtVvWwXxYy34679'
|
||||||
_font_dir = os.path.join(cfg.res_path, 'fonts')
|
# _font_dir = os.path.join(cfg.res_path, 'fonts')
|
||||||
|
|
||||||
|
|
||||||
def gen_captcha():
|
def gen_captcha():
|
||||||
|
@ -82,26 +83,79 @@ def gen_captcha():
|
||||||
curve(color='#af6fff', width=3, number=16),
|
curve(color='#af6fff', width=3, number=16),
|
||||||
noise(number=80, color='#eeeeee', level=3),
|
noise(number=80, color='#eeeeee', level=3),
|
||||||
text(fonts=[
|
text(fonts=[
|
||||||
os.path.join(_font_dir, '001.ttf')
|
os.path.join(cfg.res_path, 'fonts', '001.ttf')
|
||||||
],
|
],
|
||||||
# font_sizes=(28, 34, 36, 32),
|
# font_sizes=(28, 34, 36, 32),
|
||||||
font_sizes=(34, 36, 32),
|
font_sizes=(34, 38, 32),
|
||||||
color='#63a8f5',
|
color='#63a8f5',
|
||||||
squeeze_factor=1.2,
|
# squeeze_factor=1.2,
|
||||||
|
squeeze_factor=0.9,
|
||||||
drawings=[
|
drawings=[
|
||||||
# warp(dx_factor=0.05, dy_factor=0.05),
|
# warp(dx_factor=0.05, dy_factor=0.05),
|
||||||
rotate(angle=15),
|
warp(dx_factor=0.03, dy_factor=0.03),
|
||||||
|
rotate(angle=20),
|
||||||
offset()
|
offset()
|
||||||
]),
|
]),
|
||||||
# curve(color='#af6fff', width=3, number=16),
|
# curve(color='#af6fff', width=3, number=16),
|
||||||
noise(number=60, color='#eeeeee', level=2),
|
noise(number=30, color='#eeeeee', level=2),
|
||||||
smooth(),
|
smooth(),
|
||||||
])
|
])
|
||||||
|
|
||||||
chars_t = random.sample(_chars, 4)
|
chars_t = random.sample(_captcha_chars, 4)
|
||||||
image = captcha_image_t(chars_t)
|
image = captcha_image_t(chars_t)
|
||||||
|
|
||||||
out = io.BytesIO()
|
out = io.BytesIO()
|
||||||
image.save(out, "jpeg", quality=100)
|
image.save(out, "jpeg", quality=100)
|
||||||
# web.header('Content-Type','image/jpeg')
|
# web.header('Content-Type','image/jpeg')
|
||||||
return ''.join(chars_t), out.getvalue()
|
return ''.join(chars_t), out.getvalue()
|
||||||
|
|
||||||
|
|
||||||
|
_hex_chars = '0123456789abcdef'
|
||||||
|
|
||||||
|
|
||||||
|
def sec_generate_password(password):
|
||||||
|
"""
|
||||||
|
根据设置的password,计算一个加盐的散列,用于保存到数据库
|
||||||
|
@param password: string
|
||||||
|
@return: string
|
||||||
|
"""
|
||||||
|
|
||||||
|
_hash_type = '3' # 1 = md5, 2 = sha1, 3 = sha256
|
||||||
|
|
||||||
|
_salt_data = list()
|
||||||
|
for i in range(16):
|
||||||
|
_salt_data.append(random.choice(_hex_chars))
|
||||||
|
_salt = ''.join(_salt_data)
|
||||||
|
|
||||||
|
h = hashlib.sha256()
|
||||||
|
h.update(_hash_type.encode())
|
||||||
|
h.update(_salt.encode())
|
||||||
|
h.update(password.encode())
|
||||||
|
_val = h.hexdigest()
|
||||||
|
|
||||||
|
ret = '{}:{}:{}'.format(_hash_type, _salt, _val)
|
||||||
|
|
||||||
|
print(ret, len(ret))
|
||||||
|
return ret
|
||||||
|
|
||||||
|
|
||||||
|
def sec_verify_password(password, sec_password):
|
||||||
|
_sec = sec_password.split(':')
|
||||||
|
if len(_sec) != 3:
|
||||||
|
return False
|
||||||
|
|
||||||
|
if _sec[0] == '1':
|
||||||
|
h = hashlib.md5()
|
||||||
|
elif _sec[0] == '2':
|
||||||
|
h = hashlib.sha1()
|
||||||
|
elif _sec[0] == '3':
|
||||||
|
h = hashlib.sha256()
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
|
||||||
|
h.update(_sec[0].encode())
|
||||||
|
h.update(_sec[1].encode())
|
||||||
|
h.update(password.encode())
|
||||||
|
_val = h.hexdigest()
|
||||||
|
|
||||||
|
return _val == _sec[2]
|
||||||
|
|
|
@ -5,6 +5,7 @@ import time
|
||||||
import threading
|
import threading
|
||||||
from .base import TPBaseUserAuthHandler, TPBaseAdminAuthHandler, TPBaseAdminAuthJsonHandler
|
from .base import TPBaseUserAuthHandler, TPBaseAdminAuthHandler, TPBaseAdminAuthJsonHandler
|
||||||
from eom_app.app.db import get_db
|
from eom_app.app.db import get_db
|
||||||
|
from eom_app.app.util import sec_generate_password, sec_verify_password
|
||||||
|
|
||||||
|
|
||||||
class IndexHandler(TPBaseUserAuthHandler):
|
class IndexHandler(TPBaseUserAuthHandler):
|
||||||
|
@ -59,6 +60,7 @@ class RpcThreadManage:
|
||||||
'steps': self._threads[task_id]['steps']
|
'steps': self._threads[task_id]['steps']
|
||||||
}
|
}
|
||||||
if not self._threads[task_id]['running']:
|
if not self._threads[task_id]['running']:
|
||||||
|
print('remove task-id', task_id)
|
||||||
del self._threads[task_id]
|
del self._threads[task_id]
|
||||||
return ret
|
return ret
|
||||||
else:
|
else:
|
||||||
|
@ -71,28 +73,67 @@ class RpcThreadManage:
|
||||||
self._threads[task_id]['stop'] = True
|
self._threads[task_id]['stop'] = True
|
||||||
|
|
||||||
def _create_db(self, tid):
|
def _create_db(self, tid):
|
||||||
time.sleep(2)
|
# x = sec_generate_password('admin')
|
||||||
self._add_step_result(tid, 0, '正在初始化 1...')
|
# print(sec_verify_password('admin', x))
|
||||||
self._add_step_result(tid, 0, '正在初始化 2...')
|
# print(sec_verify_password('.admin', x))
|
||||||
self._add_step_result(tid, 0, '正在初始化 3...')
|
|
||||||
self._add_step_result(tid, 0, '正在初始化 4...')
|
def _step_begin(msg):
|
||||||
|
self._step_begin(tid, msg)
|
||||||
|
|
||||||
|
def _step_end(sid, code, msg=None):
|
||||||
|
self._step_end(tid, sid, code, msg)
|
||||||
|
|
||||||
|
time.sleep(1)
|
||||||
|
# self._add_step_result(tid, 0, '正在初始化 1...')
|
||||||
|
|
||||||
|
get_db().create_and_init(_step_begin, _step_end)
|
||||||
|
|
||||||
|
self._step_begin(tid, '操作已完成')
|
||||||
|
|
||||||
|
# time.sleep(1)
|
||||||
|
# self._add_step_result(tid, 0, '正在初始化 2...')
|
||||||
|
# time.sleep(1)
|
||||||
|
# self._add_step_result(tid, 0, '正在初始化 3...')
|
||||||
|
# time.sleep(1)
|
||||||
|
# self._add_step_result(tid, 0, '正在初始化 4...')
|
||||||
|
|
||||||
# self._threads[tid]['steps'].append({'stat': 0, 'msg': '执行已结束'})
|
# self._threads[tid]['steps'].append({'stat': 0, 'msg': '执行已结束'})
|
||||||
# if self._threads[tid]['stop']:
|
# if self._threads[tid]['stop']:
|
||||||
# self._add_step_result(tid, -1, '操作被终止')
|
# self._add_step_result(tid, -1, '操作被终止')
|
||||||
self._thread_end(tid)
|
self._thread_end(tid)
|
||||||
|
|
||||||
def _add_step_result(self, tid, code, msg):
|
def _step_begin(self, tid, msg):
|
||||||
if len(self._threads[tid]['steps']) > 0:
|
with self._lock:
|
||||||
self._threads[tid]['steps'][-1]['stat'] = 0 # 0 表示此步骤已完成
|
if len(self._threads[tid]['steps']) > 0:
|
||||||
self._threads[tid]['steps'].append({'stat': 1, 'code': code, 'msg': msg})
|
self._threads[tid]['steps'][-1]['stat'] = 0 # 0 表示此步骤已完成
|
||||||
|
self._threads[tid]['steps'].append({'stat': 1, 'code': 0, 'msg': msg})
|
||||||
|
|
||||||
|
return len(self._threads[tid]['steps']) - 1
|
||||||
|
|
||||||
|
def _step_end(self, tid, sid, code, msg=None):
|
||||||
|
with self._lock:
|
||||||
|
try:
|
||||||
|
self._threads[tid]['steps'][sid]['code'] = code
|
||||||
|
self._threads[tid]['steps'][sid]['stat'] = 0 # 0 表示此步骤已完成
|
||||||
|
if msg is not None:
|
||||||
|
self._threads[tid]['steps'][sid]['msg'] = msg
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
return len(self._threads[tid]['steps']) - 1
|
||||||
|
|
||||||
|
# def _add_step_result(self, tid, code, msg):
|
||||||
|
# if len(self._threads[tid]['steps']) > 0:
|
||||||
|
# self._threads[tid]['steps'][-1]['stat'] = 0 # 0 表示此步骤已完成
|
||||||
|
# self._threads[tid]['steps'].append({'stat': 1, 'code': code, 'msg': msg})
|
||||||
|
|
||||||
def _thread_end(self, tid):
|
def _thread_end(self, tid):
|
||||||
with self._lock:
|
with self._lock:
|
||||||
if tid in self._threads:
|
if tid in self._threads:
|
||||||
self._threads[tid]['running'] = False
|
self._threads[tid]['running'] = False
|
||||||
if self._threads[tid]['stop']:
|
if self._threads[tid]['stop']:
|
||||||
self._add_step_result(tid, -1, '操作被终止')
|
sid = self._step_begin(tid, '操作被终止')
|
||||||
|
self._step_end(tid, sid, -1)
|
||||||
if len(self._threads[tid]['steps']) > 0:
|
if len(self._threads[tid]['steps']) > 0:
|
||||||
self._threads[tid]['steps'][-1]['stat'] = 0
|
self._threads[tid]['steps'][-1]['stat'] = 0
|
||||||
|
|
||||||
|
@ -123,7 +164,7 @@ class RpcHandler(TPBaseAdminAuthJsonHandler):
|
||||||
# return self.write_json(-1)
|
# return self.write_json(-1)
|
||||||
r = thread_mgr.get_task(args['tid'])
|
r = thread_mgr.get_task(args['tid'])
|
||||||
if r is None:
|
if r is None:
|
||||||
return self.write_json(0, data={'running': False, 'msg': []})
|
return self.write_json(0, data={'running': False, 'steps': []})
|
||||||
else:
|
else:
|
||||||
# del r['stop']
|
# del r['stop']
|
||||||
return self.write_json(0, data=r)
|
return self.write_json(0, data=r)
|
||||||
|
|
|
@ -67,13 +67,23 @@
|
||||||
};
|
};
|
||||||
|
|
||||||
ywl.dom.btn_create_db.click(function () {
|
ywl.dom.btn_create_db.click(function () {
|
||||||
|
|
||||||
|
ywl.dom.btn_create_db.attr('disabled', 'disabled');
|
||||||
|
|
||||||
console.log('create-db-click');
|
console.log('create-db-click');
|
||||||
ywl.ajax_post_json('/maintenance/rpc', {cmd: 'create_db'},
|
ywl.ajax_post_json('/maintenance/rpc', {cmd: 'create_db'},
|
||||||
function (ret) {
|
function (ret) {
|
||||||
console.log('create-db:', ret);
|
console.log('create-db:', ret);
|
||||||
if (ret.code == 0) {
|
if (ret.code == 0) {
|
||||||
ywl.get_task_ret(ret.data.task_id);
|
|
||||||
}
|
var cb_stack = CALLBACK_STACK.create();
|
||||||
|
cb_stack
|
||||||
|
.add(ywl.get_task_ret, {task_id: ret.data.task_id})
|
||||||
|
.add(ywl.delay_exec, {delay_ms: 500})
|
||||||
|
.exec();
|
||||||
|
|
||||||
|
## ywl.get_task_ret(ret.data.task_id);
|
||||||
|
}
|
||||||
|
|
||||||
},
|
},
|
||||||
function () {
|
function () {
|
||||||
|
@ -83,12 +93,25 @@
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
ywl.get_task_ret = function (task_id) {
|
ywl.get_task_ret = function (cb_stack, cb_args) {
|
||||||
|
var task_id = cb_args.task_id || 0;
|
||||||
|
if (task_id == 0) {
|
||||||
|
console.log('task-id', task_id);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
ywl.ajax_post_json('/maintenance/rpc', {cmd: 'get_task_ret', 'tid': task_id},
|
ywl.ajax_post_json('/maintenance/rpc', {cmd: 'get_task_ret', 'tid': task_id},
|
||||||
function (ret) {
|
function (ret) {
|
||||||
console.log('get_task_ret:', ret);
|
console.log('get_task_ret:', ret);
|
||||||
if (ret.code == 0) {
|
if (ret.code == 0) {
|
||||||
|
if(!ret.data.running) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
cb_stack
|
||||||
|
.add(ywl.get_task_ret, {task_id: task_id})
|
||||||
|
.add(ywl.delay_exec, {delay_ms: 500})
|
||||||
|
.exec();
|
||||||
}
|
}
|
||||||
|
|
||||||
},
|
},
|
||||||
|
|
Loading…
Reference in New Issue