def delDropAddressApi(self): if not self.getFwStatus(): return mw.returnJson(False, '防火墙启动时,才能删除规则!') port = request.form.get('port', '').strip() ps = request.form.get('ps', '').strip() sid = request.form.get('id', '').strip() address = port if self.__isUfw: mw.execShell('ufw delete deny from ' + address + ' to any') else: if self.__isFirewalld: mw.execShell( 'firewall-cmd --permanent --remove-rich-rule=\'rule family=ipv4 source address="' + address + '" drop\'') elif self.__isMac: pass else: cmd = 'iptables -D INPUT -s ' + address + ' -j DROP' mw.execShell(cmd) msg = mw.getInfo('解除IP[{1}]的屏蔽!', (address,)) mw.writeLog("防火墙管理", msg) mw.M('firewall').where("id=?", (sid,)).delete() self.firewallReload() return mw.returnJson(True, '删除成功!')
def setFileAccessApi(self): if mw.isAppleSystem(): return mw.returnJson(True, '开发机不设置!') filename = request.form.get('filename', '').encode('utf-8') user = request.form.get('user', '').encode('utf-8') access = request.form.get('access', '755') sall = '-R' try: if not self.checkDir(filename): return mw.returnJson(False, '请不要花样作死') if not os.path.exists(filename): return mw.returnJson(False, '指定文件不存在!') os.system('chmod ' + sall + ' ' + access + " '" + filename + "'") os.system('chown ' + sall + ' ' + user + ':' + user + " '" + filename + "'") msg = mw.getInfo('设置[{1}]权限为[{2}]所有者为[{3}]', ( filename, access, user, )) mw.writeLog('文件管理', msg) return mw.returnJson(True, '设置成功!') except: return mw.returnJson(False, '设置失败!')
def delAcceptPortApi(self): port = request.form.get('port', '').strip() sid = request.form.get('id', '').strip() mw_port = mw.readFile('data/port.pl') try: if(port == mw_port): return mw.returnJson(False, '失败,不能删除当前面板端口!') if self.__isUfw: mw.execShell('ufw delete allow ' + port + '/tcp') else: if self.__isFirewalld: mw.execShell( 'firewall-cmd --permanent --zone=public --remove-port=' + port + '/tcp') mw.execShell( 'firewall-cmd --permanent --zone=public --remove-port=' + port + '/udp') else: mw.execShell( 'iptables -D INPUT -p tcp -m state --state NEW -m tcp --dport ' + port + ' -j ACCEPT') msg = mw.getInfo('删除防火墙放行端口[{1}]成功!', (port,)) mw.writeLog("防火墙管理", msg) mw.M('firewall').where("id=?", (sid,)).delete() self.firewallReload() return mw.returnJson(True, '删除成功!') except Exception as e: return mw.returnJson(False, '删除失败!:' + str(e))
def setSshPortApi(self): port = request.form.get('port', '1').strip() if int(port) < 22 or int(port) > 65535: return mw.returnJson(False, '端口范围必需在22-65535之间!') ports = ['21', '25', '80', '443', '7200', '8080', '888', '8888'] if port in ports: return mw.returnJson(False, '(' + port + ')' + '特殊端口不可设置!') file = '/etc/ssh/sshd_config' conf = mw.readFile(file) rep = "#*Port\s+([0-9]+)\s*\n" conf = re.sub(rep, "Port " + port + "\n", conf) mw.writeFile(file, conf) if self.__isFirewalld: mw.execShell('setenforce 0') mw.execShell( 'sed -i "s#SELINUX=enforcing#SELINUX=disabled#" /etc/selinux/config') mw.execShell("systemctl restart sshd.service") elif self.__isUfw: mw.execShell('ufw allow ' + port + '/tcp') mw.execShell("service ssh restart") else: mw.execShell( 'iptables -I INPUT -p tcp -m state --state NEW -m tcp --dport ' + port + ' -j ACCEPT') mw.execShell("/etc/init.d/sshd restart") self.firewallReload() # mw.M('firewall').where( # "ps=?", ('SSH远程管理服务',)).setField('port', port) msg = mw.getInfo('改SSH端口为[{1}]成功!', port) mw.writeLog("防火墙管理", msg) return mw.returnJson(True, '修改成功!')
def addDropAddressApi(self): import re port = request.form.get('port', '').strip() ps = request.form.get('ps', '').strip() rep = "^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}(\/\d{1,2})?$" if not re.search(rep, port): return mw.returnJson(False, '您输入的IP地址不合法!') address = port if mw.M('firewall').where("port=?", (address,)).count() > 0: return mw.returnJson(False, '您要放屏蔽的IP已存在屏蔽列表,无需重复处理!') if self.__isUfw: mw.execShell('ufw deny from ' + address + ' to any') else: if self.__isFirewalld: cmd = 'firewall-cmd --permanent --add-rich-rule=\'rule family=ipv4 source address="' + \ address + '" drop\'' mw.execShell(cmd) else: cmd = 'iptables -I INPUT -s ' + address + ' -j DROP' mw.execShell(cmd) msg = mw.getInfo('屏蔽IP[{1}]成功!', (address,)) mw.writeLog("防火墙管理", msg) addtime = time.strftime('%Y-%m-%d %X', time.localtime()) mw.M('firewall').add('port,ps,addtime', (address, ps, addtime)) self.firewallReload() return mw.returnJson(True, '添加成功!')
def addAcceptPortApi(self): if not self.getFwStatus(): return mw.returnJson(False, '防火墙启动时,才能添加规则!') import re import time port = request.form.get('port', '').strip() ps = request.form.get('ps', '').strip() stype = request.form.get('type', '').strip() rep = "^\d{1,5}(:\d{1,5})?$" if not re.search(rep, port): return mw.returnJson(False, '端口范围不正确!') if mw.M('firewall').where("port=?", (port,)).count() > 0: return mw.returnJson(False, '您要放行的端口已存在,无需重复放行!') msg = mw.getInfo('放行端口[{1}]成功', (port,)) mw.writeLog("防火墙管理", msg) addtime = time.strftime('%Y-%m-%d %X', time.localtime()) mw.M('firewall').add('port,ps,addtime', (port, ps, addtime)) self.addAcceptPort(port) self.firewallReload() return mw.returnJson(True, '添加放行(' + port + ')端口成功!')
def closeLogsApi(self): logPath = mw.getLogsDir() os.system('rm -f ' + logPath + '/*') os.system('kill -USR1 `cat ' + mw.getServerDir() + 'openresty/nginx/logs/nginx.pid`') mw.writeLog('文件管理', '网站日志已被清空!') tmp = self.getDirSize(logPath) return mw.returnJson(True, tmp[0].split()[0])
def backupSite(self, name, count): sql = db.Sql() path = sql.table('sites').where('name=?', (name, )).getField('path') startTime = time.time() if not path: endDate = time.strftime('%Y/%m/%d %X', time.localtime()) log = u"网站[" + name + "]不存在!" print(u"★[" + endDate + "] " + log) print( "----------------------------------------------------------------------------" ) return backup_path = mw.getRootDir() + '/backup/site' if not os.path.exists(backup_path): mw.execShell("mkdir -p " + backup_path) filename = backup_path + "/web_" + name + "_" + \ time.strftime('%Y%m%d_%H%M%S', time.localtime()) + '.tar.gz' mw.execShell("cd " + os.path.dirname(path) + " && tar zcvf '" + filename + "' '" + os.path.basename(path) + "' > /dev/null") endDate = time.strftime('%Y/%m/%d %X', time.localtime()) print filename if not os.path.exists(filename): log = u"网站[" + name + u"]备份失败!" print(u"★[" + endDate + "] " + log) print( u"----------------------------------------------------------------------------" ) return outTime = time.time() - startTime pid = sql.table('sites').where('name=?', (name, )).getField('id') sql.table('backup').add('type,name,pid,filename,addtime,size', ('0', os.path.basename(filename), pid, filename, endDate, os.path.getsize(filename))) log = u"网站[" + name + u"]备份成功,用时[" + str(round(outTime, 2)) + u"]秒" mw.writeLog(u'计划任务', log) print(u"★[" + endDate + "] " + log) print(u"|---保留最新的[" + count + u"]份备份") print(u"|---文件名:" + filename) # 清理多余备份 backups = sql.table('backup').where( 'type=? and pid=?', ('0', pid)).field('id,filename').select() num = len(backups) - int(count) if num > 0: for backup in backups: mw.execShell("rm -f " + backup['filename']) sql.table('backup').where('id=?', (backup['id'], )).delete() num -= 1 print(u"|---已清理过期备份文件:" + backup['filename']) if num < 1: break
def batchPasteApi(self): path = request.form.get('path', '').encode('utf-8') stype = request.form.get('type', '').encode('utf-8') # filename = request.form.get('filename', '').encode('utf-8') import shutil if not self.checkDir(path): return mw.returnJson(False, '请不要花样作死!') i = 0 myfiles = json.loads(session['selected']['data']) l = len(myfiles) if stype == '1': for key in myfiles: i += 1 mw.writeSpeed(key, i, l) try: sfile = session['selected']['path'] + '/' + key.encode( 'utf-8') dfile = path + '/' + key.encode('utf-8') if os.path.isdir(sfile): shutil.copytree(sfile, dfile) else: shutil.copyfile(sfile, dfile) stat = os.stat(sfile) os.chown(dfile, stat.st_uid, stat.st_gid) except: continue msg = mw.getInfo('从[{1}]批量复制到[{2}]成功', ( session['selected']['path'], path, )) mw.writeLog('文件管理', msg) else: for key in myfiles: try: i += 1 mw.writeSpeed(key, i, l) sfile = session['selected']['path'] + '/' + key.encode( 'utf-8') dfile = path + '/' + key.encode('utf-8') shutil.move(sfile, dfile) except: continue msg = mw.getInfo('从[{1}]批量移动到[{2}]成功', ( session['selected']['path'], path, )) mw.writeLog('文件管理', msg) mw.writeSpeed(None, 0, 0) errorCount = len(myfiles) - i del (session['selected']) msg = mw.getInfo('批量操作成功[{1}],失败[{2}]', (str(i), str(errorCount))) return mw.returnJson(True, msg)
def setIpv6StatusApi(self): ipv6_file = 'data/ipv6.pl' if os.path.exists('data/ipv6.pl'): os.remove(ipv6_file) mw.writeLog('面板设置', '关闭面板IPv6兼容!') else: mw.writeFile(ipv6_file, 'True') mw.writeLog('面板设置', '开启面板IPv6兼容!') mw.restartMw() return mw.returnJson(True, '设置成功!')
def doLogin(): username = request.form.get('username', '').strip() password = request.form.get('password', '').strip() code = request.form.get('code', '').strip() # print(session) if 'code' in session: if session['code'] != mw.md5(code): return mw.returnJson(False, '验证码错误,请重新输入!') userInfo = mw.M('users').where("id=?", (1, )).field('id,username,password').find() # print(userInfo) # print(password) password = mw.md5(password) # print('md5-pass', password) login_cache_count = 5 login_cache_limit = cache.get('login_cache_limit') filename = 'data/close.pl' if os.path.exists(filename): return mw.returnJson(False, '面板已经关闭!') if userInfo['username'] != username or userInfo['password'] != password: msg = "<a style='color: red'>密码错误</a>,帐号:{1},密码:{2},登录IP:{3}", (( '****', '******', request.remote_addr)) if login_cache_limit == None: login_cache_limit = 1 else: login_cache_limit = int(login_cache_limit) + 1 if login_cache_limit >= login_cache_count: mw.writeFile(filename, 'True') return mw.returnJson(False, '面板已经关闭!') cache.set('login_cache_limit', login_cache_limit, timeout=10000) login_cache_limit = cache.get('login_cache_limit') mw.writeLog('用户登录', mw.getInfo(msg)) return mw.returnJson( False, mw.getInfo("用户名或密码错误,您还可以尝试[{1}]次!", (str(login_cache_count - login_cache_limit)))) cache.delete('login_cache_limit') session['login'] = True session['username'] = userInfo['username'] #print('do_login', session) # fix 跳转时,数据消失,可能是跨域问题 mw.writeFile('data/api_login.txt', userInfo['username']) return mw.returnJson(True, '登录成功,正在跳转...')
def recycleBinApi(self): c = 'data/recycle_bin.pl' db = request.form.get('db', '').encode('utf-8') if db != '': c = 'data/recycle_bin_db.pl' if os.path.exists(c): os.remove(c) mw.writeLog('文件管理', '已关闭回收站功能!') return mw.returnJson(True, '已关闭回收站功能!') else: mw.writeFile(c, 'True') mw.writeLog('文件管理', '已开启回收站功能!') return mw.returnJson(True, '已开启回收站功能!')
def delFtp(): args = getArgs() if not 'id' in args: return 'ftp_username missing' if not 'username' in args: return 'username missing' mw.execShell(getServerDir() + '/bin/pure-pw userdel ' + args['username']) pftpReload() conn = pftpDB() conn.where("id=?", (args['id'], )).delete() mw.writeLog('TYPE_FTP', 'FTP_DEL_SUCCESS', (args['username'], )) return 'ok'
def createDirApi(self): path = request.form.get('path', '').encode('utf-8') try: if not self.checkFileName(path): return mw.returnJson(False, '目录名中不能包含特殊字符!') if os.path.exists(path): return mw.returnJson(False, '指定目录已存在!') os.makedirs(path) self.setFileAccept(path) msg = mw.getInfo('创建目录[{1}]成功!', (path, )) mw.writeLog('文件管理', msg) return mw.returnJson(True, '目录创建成功!') except Exception as e: return mw.returnJson(False, '目录创建失败!')
def mvRecycleBin(self, path): rPath = self.rPath if not os.path.exists(rPath): os.system('mkdir -p ' + rPath) rFile = rPath + path.replace('/', '_mw_') + '_t_' + str(time.time()) try: import shutil shutil.move(path, rFile) mw.writeLog('文件管理', mw.getInfo('移动文件[{1}]到回收站成功!', (path))) return True except: mw.writeLog('文件管理', mw.getInfo('移动文件[{1}]到回收站失败!', (path))) return False
def reRecycleBinApi(self): rPath = self.rPath path = request.form.get('path', '').encode('utf-8') dFile = path.replace('_mw_', '/').split('_t_')[0] try: import shutil shutil.move(rPath + path, dFile) msg = mw.getInfo('移动文件[{1}]到回收站成功!', (dFile, )) mw.writeLog('文件管理', msg) return mw.returnJson(True, '恢复成功!') except Exception as e: msg = mw.getInfo('从回收站恢复[{1}]失败!', (dFile, )) mw.writeLog('文件管理', msg) return mw.returnJson(False, '恢复失败!')
def check502(): try: phpversions = ['53', '54', '55', '56', '70', '71', '72', '73', '74'] for version in phpversions: sdir = mw.getServerDir() php_path = sdir + '/php/' + version + '/sbin/php-fpm' if not os.path.exists(php_path): continue if checkPHPVersion(version): continue if startPHPVersion(version): print '检测到PHP-' + version + '处理异常,已自动修复!' mw.writeLog('PHP守护程序', '检测到PHP-' + version + '处理异常,已自动修复!') except Exception as e: print str(e)
def copyDir(self, sfile, dfile): if not os.path.exists(sfile): return mw.returnJson(False, '指定目录不存在!') if os.path.exists(dfile): return mw.returnJson(False, '指定目录已存在!') import shutil try: shutil.copytree(sfile, dfile) stat = os.stat(sfile) os.chown(dfile, stat.st_uid, stat.st_gid) msg = mw.getInfo('复制目录[{1}]到[{2}]成功!', (sfile, dfile)) mw.writeLog('文件管理', msg) return mw.returnJson(True, '目录复制成功!') except: return mw.returnJson(False, '目录复制失败!')
def deleteDirApi(self): path = request.form.get('path', '').encode('utf-8') if not os.path.exists(path): return mw.returnJson(False, '指定文件不存在!') # 检查是否为.user.ini if path.find('.user.ini'): os.system("chattr -i '" + path + "'") try: if os.path.exists('data/recycle_bin.pl'): if self.mvRecycleBin(path): return mw.returnJson(True, '已将文件移动到回收站!') mw.execShell('rm -rf ' + path) mw.writeLog('文件管理', '删除文件成功!', (path, )) return mw.returnJson(True, '删除文件成功!') except: return mw.returnJson(False, '删除文件失败!')
def closeRecycleBinApi(self): rPath = self.rPath os.system('which chattr && chattr -R -i ' + rPath) rlist = os.listdir(rPath) i = 0 l = len(rlist) for name in rlist: i += 1 path = rPath + name mw.writeSpeed(name, i, l) if os.path.isdir(path): shutil.rmtree(path) else: os.remove(path) mw.writeSpeed(None, 0, 0) mw.writeLog('文件管理', '已清空回收站!') return mw.returnJson(True, '已清空回收站!')
def inputZipApi(self): plugin_name = request.form.get('plugin_name', '') tmp_path = request.form.get('tmp_path', '') if not os.path.exists(tmp_path): return mw.returnJson(False, '临时文件不存在,请重新上传!') plugin_path = mw.getPluginDir() + '/' + plugin_name if not os.path.exists(plugin_path): print(mw.execShell('mkdir -p ' + plugin_path)) mw.execShell("\cp -rf " + tmp_path + '/* ' + plugin_path + '/') mw.execShell('chmod -R 755 ' + plugin_path) p_info = mw.readFile(plugin_path + '/info.json') if p_info: mw.writeLog('软件管理', '安装第三方插件[%s]' % json.loads(p_info)['title']) return mw.returnJson(True, '安装成功!') mw.execShell("rm -rf " + plugin_path) return mw.returnJson(False, '安装失败!')
def mainSafe(): global isCheck try: if isCheck < 100: isCheck += 1 return True isCheck = 0 isStart = mw.execShell( "ps aux |grep 'python main.py'|grep -v grep|awk '{print $2}'")[0] if not isStart: os.system('/etc/init.d/bt start') isStart = mw.execShell( "ps aux |grep 'python main.py'|grep -v grep|awk '{print $2}'")[0] mw.writeLog('守护程序', '面板服务程序启动成功 -> PID: ' + isStart) except: time.sleep(30) mainSafe()
def setFpmConfig(version): args = getArgs() # if not 'max' in args: # return 'missing time args!' version = args['version'] max_children = args['max_children'] start_servers = args['start_servers'] min_spare_servers = args['min_spare_servers'] max_spare_servers = args['max_spare_servers'] pm = args['pm'] file = getServerDir() + '/' + version + '/etc/php-fpm.d/www.conf' conf = mw.readFile(file) rep = "\s*pm.max_children\s*=\s*([0-9]+)\s*" conf = re.sub(rep, "\npm.max_children = " + max_children, conf) rep = "\s*pm.start_servers\s*=\s*([0-9]+)\s*" conf = re.sub(rep, "\npm.start_servers = " + start_servers, conf) rep = "\s*pm.min_spare_servers\s*=\s*([0-9]+)\s*" conf = re.sub(rep, "\npm.min_spare_servers = " + min_spare_servers, conf) rep = "\s*pm.max_spare_servers \s*=\s*([0-9]+)\s*" conf = re.sub(rep, "\npm.max_spare_servers = " + max_spare_servers + "\n", conf) rep = "\s*pm\s*=\s*(\w+)\s*" conf = re.sub(rep, "\npm = " + pm + "\n", conf) mw.writeFile(file, conf) reload(version) msg = mw.getInfo( '设置PHP-{1}并发设置,max_children={2},start_servers={3},min_spare_servers={4},max_spare_servers={5}', ( version, max_children, start_servers, min_spare_servers, max_spare_servers, )) mw.writeLog('插件管理[PHP]', msg) return mw.returnJson(True, '设置成功!')
def delete(self, path): if not os.path.exists(path): return mw.returnJson(False, '指定文件不存在!') # 检查是否为.user.ini if path.find('.user.ini') >= 0: os.system("chattr -i '" + path + "'") try: if os.path.exists('data/recycle_bin.pl'): if self.mvRecycleBin(path): return mw.returnJson(True, '已将文件移动到回收站!') os.remove(path) mw.writeLog('文件管理', mw.getInfo('删除文件[{1}]成功!', (path))) return mw.returnJson(True, '删除文件成功!') except: return mw.returnJson(False, '删除文件失败!')
def createFileApi(self): file = request.form.get('path', '').encode('utf-8') try: if not self.checkFileName(file): return mw.returnJson(False, '文件名中不能包含特殊字符!') if os.path.exists(file): return mw.returnJson(False, '指定文件已存在!') _path = os.path.dirname(file) if not os.path.exists(_path): os.makedirs(_path) open(file, 'w+').close() self.setFileAccept(file) msg = mw.getInfo('创建文件[{1}]成功!', (file, )) mw.writeLog('文件管理', msg) return mw.returnJson(True, '文件创建成功!') except Exception as e: # print str(e) return mw.returnJson(True, '文件创建失败!')
def saveBody(self, path, data, encoding='utf-8'): if not os.path.exists(path): return mw.returnJson(False, '文件不存在') try: if encoding == 'ascii': encoding = 'utf-8' if sys.version_info[0] == 2: data = data.encode(encoding, errors='ignore') fp = open(path, 'w+') else: data = data.encode(encoding, errors='ignore').decode(encoding) fp = open(path, 'w+', encoding=encoding) fp.write(data) fp.close() mw.writeLog('文件管理', '文件保存成功', (path, )) return mw.returnJson(True, '文件保存成功') except Exception as ex: return mw.returnJson(False, 'FILE_SAVE_ERR:' + str(ex))
def delRecycleBinApi(self): rPath = self.rPath path = request.form.get('path', '').encode('utf-8') empty = request.form.get('empty', '').encode('utf-8') dFile = path.split('_t_')[0] if not self.checkDir(path): return mw.returnJson(False, '敏感目录,请不要花样作死!') os.system('which chattr && chattr -R -i ' + rPath + path) if os.path.isdir(rPath + path): import shutil shutil.rmtree(rPath + path) else: os.remove(rPath + path) tfile = path.replace('_mw_', '/').split('_t_')[0] msg = mw.getInfo('已彻底从回收站删除{1}!', (tfile, )) mw.writeLog('文件管理', msg) return mw.returnJson(True, msg)
def setDisableFunc(version): filename = mw.getServerDir() + '/php/' + version + '/etc/php.ini' if not os.path.exists(filename): return mw.returnJson(False, '指定PHP版本不存在!') args = getArgs() disable_functions = args['disable_functions'] phpini = mw.readFile(filename) rep = "disable_functions\s*=\s*.*\n" phpini = re.sub(rep, 'disable_functions = ' + disable_functions + "\n", phpini) msg = mw.getInfo('修改PHP-{1}的禁用函数为[{2}]', ( version, disable_functions, )) mw.writeLog('插件管理[PHP]', msg) mw.writeFile(filename, phpini) reload(version) return mw.returnJson(True, '设置成功!')
def setMaxSize(version): args = getArgs() if not 'max' in args: return 'missing time args!' max = args['max'] if int(max) < 2: return mw.returnJson(False, '上传大小限制不能小于2MB!') path = getServerDir() + '/' + version + '/etc/php.ini' conf = mw.readFile(path) rep = u"\nupload_max_filesize\s*=\s*[0-9]+M" conf = re.sub(rep, u'\nupload_max_filesize = ' + max + 'M', conf) rep = u"\npost_max_size\s*=\s*[0-9]+M" conf = re.sub(rep, u'\npost_max_size = ' + max + 'M', conf) mw.writeFile(path, conf) msg = mw.getInfo('设置PHP-{1}最大上传大小为[{2}MB]!', ( version, max, )) mw.writeLog('插件管理[PHP]', msg) return mw.returnJson(True, '设置成功!')
def setSshStatusApi(self): if mw.isAppleSystem(): return mw.returnJson(True, '开发机不能操作!') status = request.form.get('status', '1').strip() version = mw.readFile('/etc/redhat-release') if int(status) == 1: msg = 'SSH服务已停用' act = 'stop' else: msg = 'SSH服务已启用' act = 'start' if not os.path.exists('/etc/redhat-release'): mw.execShell('service ssh ' + act) elif version.find(' 7.') != -1: mw.execShell("systemctl " + act + " sshd.service") else: mw.execShell("/etc/init.d/sshd " + act) mw.writeLog("防火墙管理", msg) return mw.returnJson(True, '操作成功!')