mirror of https://github.com/IoTcat/PyOne.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
566 lines
20 KiB
566 lines
20 KiB
|
|
#-*- coding=utf-8 -*- |
|
from flask import Flask,render_template,redirect,abort,make_response,jsonify,request,url_for,Response |
|
from flask_sqlalchemy import Pagination |
|
import json |
|
from collections import OrderedDict |
|
import subprocess |
|
import hashlib |
|
import random |
|
import markdown |
|
from function import * |
|
from config import * |
|
from flask_caching import Cache |
|
from flask_limiter import Limiter |
|
from flask_limiter.util import get_remote_address |
|
from shelljob import proc |
|
import time |
|
import os |
|
import sys |
|
import eventlet |
|
|
|
eventlet.monkey_patch() |
|
|
|
reload(sys) |
|
sys.setdefaultencoding("utf-8") |
|
|
|
|
|
#######flask |
|
app=Flask(__name__) |
|
app.secret_key=os.path.join(config_dir,'PyOne'+password) |
|
cache = Cache(app, config={'CACHE_TYPE': 'redis'}) |
|
limiter = Limiter( |
|
app, |
|
key_func=get_remote_address, |
|
default_limits=["200/minute", "50/second"], |
|
) |
|
|
|
|
|
################################################################################ |
|
###################################功能函数##################################### |
|
################################################################################ |
|
def md5(string): |
|
a=hashlib.md5() |
|
a.update(string.encode(encoding='utf-8')) |
|
return a.hexdigest() |
|
|
|
def GetTotal(path='A:/'): |
|
key='total:{}'.format(path) |
|
if rd.exists(key): |
|
return int(rd.get(key)) |
|
else: |
|
user,n_path=path.split(':') |
|
if n_path=='/': |
|
total=items.find({'grandid':0}).count() |
|
else: |
|
f=items.find_one({'path':path}) |
|
pid=f['id'] |
|
total=items.find({'parent':pid}).count() |
|
rd.set(key,total,300) |
|
return total |
|
|
|
|
|
# @cache.memoize(timeout=60*5) |
|
def FetchData(path='A:/',page=1,per_page=50,sortby='lastModtime',order='desc',dismiss=False): |
|
path=urllib.unquote(path) |
|
resp=[] |
|
if sortby not in ['lastModtime','type','size','name']: |
|
sortby='lastModtime' |
|
if sortby=='size': |
|
sortby='size_order' |
|
if order=='desc': |
|
order=DESCENDING |
|
else: |
|
order=ASCENDING |
|
try: |
|
user,n_path=path.split(':') |
|
if n_path=='/': |
|
data=items.find({'grandid':0,'user':user}).collation({"locale": "zh", 'numericOrdering':True})\ |
|
.sort([('order',ASCENDING),(sortby,order)])\ |
|
.limit(per_page).skip((page-1)*per_page) |
|
for d in data: |
|
item={} |
|
item['name']=d['name'] |
|
item['id']=d['id'] |
|
item['lastModtime']=d['lastModtime'] |
|
item['size']=d['size'] |
|
item['type']=d['type'] |
|
if dismiss: |
|
if d['name'] not in ('README.md','README.txt','readme.md','readme.txt','.password','HEAD.md','HEAD.txt','head.md','head.txt'): |
|
resp.append(item) |
|
else: |
|
resp.append(item) |
|
total=GetTotal(path) |
|
else: |
|
f=items.find_one({'path':path}) |
|
pid=f['id'] |
|
if f['type']!='folder': |
|
return f,'files' |
|
data=items.find({'parent':pid}).collation({"locale": "zh", 'numericOrdering':True})\ |
|
.sort([('order',ASCENDING),(sortby,order)])\ |
|
.limit(per_page).skip((page-1)*per_page) |
|
for d in data: |
|
item={} |
|
item['name']=d['name'] |
|
item['id']=d['id'] |
|
item['lastModtime']=d['lastModtime'] |
|
item['size']=d['size'] |
|
item['type']=d['type'] |
|
if dismiss: |
|
if d['name'] not in ('README.md','README.txt','readme.md','readme.txt','.password','HEAD.md','HEAD.txt','head.md','head.txt'): |
|
resp.append(item) |
|
else: |
|
resp.append(item) |
|
total=GetTotal(path) |
|
except: |
|
resp=[] |
|
total=0 |
|
return resp,total |
|
|
|
@cache.memoize(timeout=60*5) |
|
def _thunbnail(id,user): |
|
app_url=GetAppUrl() |
|
token=GetToken(user=user) |
|
headers={'Authorization':'bearer {}'.format(token),'Content-type':'application/json'} |
|
url=app_url+'v1.0/me/drive/items/{}/thumbnails/0?select=large'.format(id) |
|
r=requests.get(url,headers=headers) |
|
data=json.loads(r.content) |
|
if data.get('large').get('url'): |
|
return data.get('large').get('url') |
|
else: |
|
return False |
|
|
|
@cache.memoize(timeout=60*5) |
|
def _getdownloadurl(id,user): |
|
app_url=GetAppUrl() |
|
token=GetToken(user=user) |
|
filename=GetName(id) |
|
ext=filename.split('.')[-1] |
|
if ext in ['webm','avi','mpg', 'mpeg', 'rm', 'rmvb', 'mov', 'wmv', 'mkv', 'asf']: |
|
downloadUrl=_thunbnail(id,user) |
|
downloadUrl=downloadUrl.replace('thumbnail','videomanifest')+'&part=index&format=dash&useScf=True&pretranscode=0&transcodeahead=0' |
|
return downloadUrl |
|
else: |
|
headers={'Authorization':'bearer {}'.format(token),'Content-type':'application/json'} |
|
url=app_url+'v1.0/me/drive/items/'+id |
|
r=requests.get(url,headers=headers) |
|
data=json.loads(r.content) |
|
if data.get('@microsoft.graph.downloadUrl'): |
|
return data.get('@microsoft.graph.downloadUrl') |
|
else: |
|
return False |
|
|
|
def GetDownloadUrl(id,user): |
|
if rd.exists('downloadUrl2:{}'.format(id)): |
|
downloadUrl,ftime=rd.get('downloadUrl2:{}'.format(id)).split('####') |
|
if time.time()-int(ftime)>=600: |
|
# print('{} downloadUrl expired!'.format(id)) |
|
downloadUrl=_getdownloadurl(id,user) |
|
ftime=int(time.time()) |
|
k='####'.join([downloadUrl,str(ftime)]) |
|
rd.set('downloadUrl2:{}'.format(id),k) |
|
else: |
|
# print('get {}\'s downloadUrl from cache'.format(id)) |
|
downloadUrl=downloadUrl |
|
else: |
|
# print('first time get downloadUrl from {}'.format(id)) |
|
downloadUrl=_getdownloadurl(id,user) |
|
ftime=int(time.time()) |
|
k='####'.join([downloadUrl,str(ftime)]) |
|
rd.set('downloadUrl2:{}'.format(id),k) |
|
return downloadUrl |
|
|
|
|
|
|
|
# @cache.memoize(timeout=60*5) |
|
def GetReadMe(path): |
|
# README |
|
ext='Markdown' |
|
readme,_,i=has_item(path,'README.md') |
|
if readme==False: |
|
readme,_,i=has_item(path,'readme.md') |
|
if readme==False: |
|
ext='Text' |
|
readme,_,i=has_item(path,'readme.txt') |
|
if readme==False: |
|
ext='Text' |
|
readme,_,i=has_item(path,'README.txt') |
|
if readme!=False: |
|
readme=markdown.markdown(readme) |
|
return readme,ext |
|
|
|
|
|
# @cache.memoize(timeout=60*5) |
|
def GetHead(path): |
|
# README |
|
ext='Markdown' |
|
head,_,i=has_item(path,'HEAD.md') |
|
if head==False: |
|
head,_,i=has_item(path,'head.md') |
|
if head==False: |
|
ext='Text' |
|
head,_,i=has_item(path,'head.txt') |
|
if head==False: |
|
ext='Text' |
|
head,_,i=has_item(path,'HEAD.txt') |
|
if head!=False: |
|
head=markdown.markdown(head) |
|
return head,ext |
|
|
|
|
|
def CanEdit(filename): |
|
ext=filename.split('.')[-1] |
|
if ext in ["html","htm","php","css","go","java","js","json","txt","sh","md",".password"]: |
|
return True |
|
else: |
|
return False |
|
|
|
def CodeType(ext): |
|
code_type={} |
|
code_type['html'] = 'html'; |
|
code_type['htm'] = 'html'; |
|
code_type['php'] = 'php'; |
|
code_type['css'] = 'css'; |
|
code_type['go'] = 'golang'; |
|
code_type['java'] = 'java'; |
|
code_type['js'] = 'javascript'; |
|
code_type['json'] = 'json'; |
|
code_type['txt'] = 'Text'; |
|
code_type['sh'] = 'sh'; |
|
code_type['md'] = 'Markdown'; |
|
return code_type.get(ext.lower()) |
|
|
|
def file_ico(item): |
|
ext = item['name'].split('.')[-1].lower() |
|
if ext in ['bmp','jpg','jpeg','png','gif']: |
|
return "image"; |
|
|
|
if ext in ['mp4','mkv','webm','avi','mpg', 'mpeg', 'rm', 'rmvb', 'mov', 'wmv', 'mkv', 'asf']: |
|
return "ondemand_video"; |
|
|
|
if ext in ['ogg','mp3','wav']: |
|
return "audiotrack"; |
|
|
|
return "insert_drive_file"; |
|
|
|
def _remote_content(fileid,user): |
|
kc='{}:content'.format(fileid) |
|
if rd.exists(kc): |
|
return rd.get(kc) |
|
else: |
|
downloadUrl=GetDownloadUrl(fileid,user) |
|
if downloadUrl: |
|
r=requests.get(downloadUrl) |
|
r.encoding='utf-8' |
|
content=r.content |
|
rd.set(kc,content) |
|
return content |
|
else: |
|
return False |
|
|
|
# @cache.memoize(timeout=60) |
|
def has_item(path,name): |
|
if items.count()==0: |
|
return False,False,False |
|
key='has_item$#$#$#$#{}$#$#$#$#{}'.format(path,name) |
|
if rd.exists(key): |
|
values=rd.get(key) |
|
item,fid,cur=values.split('########') |
|
if item=='False': |
|
item=False |
|
if cur=='False': |
|
cur=False |
|
else: |
|
cur=True |
|
if fid=='False': |
|
fid=False |
|
return item,fid,cur |
|
else: |
|
item=False |
|
fid=False |
|
dz=False |
|
cur=False |
|
if name=='.password': |
|
dz=True |
|
try: |
|
user,n_path=path.split(':') |
|
if n_path=='/': |
|
if items.find_one({'grandid':0,'name':name,'user':user}): |
|
fid=items.find_one({'grandid':0,'name':name,'user':user})['id'] |
|
item=_remote_content(fid,user).strip() |
|
else: |
|
route=path.split('/') |
|
if name=='.password': |
|
for idx,r in enumerate(route): |
|
p='/'.join(route[:idx+1]) |
|
f=items.find_one({'path':p}) |
|
pid=f['id'] |
|
data=items.find_one({'name':name,'parent':pid}) |
|
if data: |
|
fid=data['id'] |
|
item=_remote_content(fid,user).strip() |
|
if idx==len(route)-1: |
|
cur=True |
|
else: |
|
f=items.find_one({'path':path}) |
|
pid=f['id'] |
|
data=items.find_one({'name':name,'parent':pid}) |
|
if data: |
|
fid=data['id'] |
|
item=_remote_content(fid,user).strip() |
|
except: |
|
item=False |
|
rd.set(key,'{}########{}########{}'.format(item,fid,cur)) |
|
return item,fid,cur |
|
|
|
|
|
def verify_pass_before(path): |
|
plist=path_list(path) |
|
for i in [i for i in range(len(plist))]: |
|
n='/'.join(plist[:-i]) |
|
yield n |
|
|
|
def has_verify(path): |
|
verify=False |
|
md5_p=md5(path) |
|
passwd,fid,cur=has_item(path,'.password') |
|
if fid and cur: |
|
vp=request.cookies.get(md5_p) |
|
if passwd==vp: |
|
verify=True |
|
else: |
|
for last in verify_pass_before(path): |
|
if last=='': |
|
last='/' |
|
passwd,fid,cur=has_item(last,'.password') |
|
md5_p=md5(last) |
|
vp=request.cookies.get(md5_p) |
|
if passwd==vp: |
|
verify=True |
|
return verify |
|
|
|
|
|
def path_list(path): |
|
if path.split(':')=='': |
|
plist=[path+'/'] |
|
else: |
|
user,n_path=path.split(':') |
|
if n_path.startswith('/'): |
|
n_path=n_path[1:] |
|
if n_path.endswith('/'): |
|
n_path=n_path[:-1] |
|
plist=n_path.split('/') |
|
plist=['{}:/{}'.format(user,plist[0])]+plist[1:] |
|
return plist |
|
|
|
|
|
|
|
def get_od_user(): |
|
config_path=os.path.join(config_dir,'config.py') |
|
with open(config_path,'r') as f: |
|
text=f.read() |
|
users=json.loads(re.findall('od_users=([\w\W]*})',text)[0]) |
|
ret=[] |
|
for user,value in users.items(): |
|
if value.get('client_id')!='': |
|
#userid,username,endpoint,sharepath,order, |
|
ret.append( |
|
( |
|
user, |
|
value.get('other_name'), |
|
'/{}:'.format(user), |
|
value.get('share_path'), |
|
value.get('order') |
|
) |
|
) |
|
else: |
|
ret.append( |
|
( |
|
user, |
|
'添加网盘', |
|
url_for('admin.install',step=0,user=user), |
|
value.get('share_path'), |
|
value.get('order') |
|
) |
|
) |
|
ret=sorted(ret,key=lambda x:x[-1],reverse=False) |
|
return ret |
|
|
|
|
|
|
|
|
|
################################################################################ |
|
###################################试图函数##################################### |
|
################################################################################ |
|
@app.before_request |
|
def before_request(): |
|
bad_ua=['Googlebot-Image','FeedDemon ','BOT/0.1 (BOT for JCE)','CrawlDaddy ','Java','Feedly','UniversalFeedParser','ApacheBench','Swiftbot','ZmEu','Indy Library','oBot','jaunty','YandexBot','AhrefsBot','MJ12bot','WinHttp','EasouSpider','HttpClient','Microsoft URL Control','YYSpider','jaunty','Python-urllib','lightDeckReports Bot','PHP','vxiaotou-spider','spider'] |
|
global referrer |
|
try: |
|
ip = request.headers['X-Forwarded-For'].split(',')[0] |
|
except: |
|
ip = request.remote_addr |
|
try: |
|
ua = request.headers.get('User-Agent') |
|
except: |
|
ua="null" |
|
if sum([i.lower() in ua.lower() for i in bad_ua])>0: |
|
return redirect('http://www.baidu.com') |
|
# print '{}:{}:{}'.format(request.endpoint,ip,ua) |
|
referrer=request.referrer if request.referrer is not None else 'no-referrer' |
|
|
|
@app.route('/<path:path>',methods=['POST','GET']) |
|
@app.route('/',methods=['POST','GET']) |
|
@limiter.limit("200/minute;50/second") |
|
def index(path='A:/'): |
|
if path=='favicon.ico': |
|
return redirect('https://onedrive.live.com/favicon.ico') |
|
if items.count()==0: |
|
if not os.path.exists(os.path.join(config_dir,'data/.install')): |
|
return redirect(url_for('admin.install',step=0,user='A')) |
|
else: |
|
#subprocess.Popen('python {} UpdateFile'.format(os.path.join(config_dir,'function.py')),shell=True) |
|
return make_response('<h1>正在更新数据!如果您是网站管理员,请在后台运行命令:python function.py UpdateFile</h1>') |
|
#参数 |
|
user,n_path=path.split(':') |
|
if n_path=='': |
|
path=':'.join([user,'/']) |
|
page=request.args.get('page',1,type=int) |
|
image_mode=request.args.get('image_mode') |
|
sortby=request.args.get('sortby') |
|
order=request.args.get('order') |
|
resp,total = FetchData(path=path,page=page,per_page=50,sortby=sortby,order=order,dismiss=True) |
|
if total=='files': |
|
return show(resp['id'],user) |
|
#是否有密码 |
|
password,_,cur=has_item(path,'.password') |
|
md5_p=md5(path) |
|
has_verify_=has_verify(path) |
|
if request.method=="POST": |
|
password1=request.form.get('password') |
|
if password1==password: |
|
resp=make_response(redirect(url_for('.index',path=path))) |
|
resp.delete_cookie(md5_p) |
|
resp.set_cookie(md5_p,password) |
|
return resp |
|
if password!=False: |
|
if (not request.cookies.get(md5_p) or request.cookies.get(md5_p)!=password) and has_verify_==False: |
|
return render_template('password.html',path=path) |
|
readme,ext_r=GetReadMe(path) |
|
head,ext_d=GetHead(path) |
|
#设置cookies |
|
if image_mode: |
|
image_mode=request.args.get('image_mode',type=int) |
|
else: |
|
image_mode=request.cookies.get('image_mode') if request.cookies.get('image_mode') is not None else 0 |
|
image_mode=int(image_mode) |
|
if sortby: |
|
sortby=request.args.get('sortby') |
|
else: |
|
sortby=request.cookies.get('sortby') if request.cookies.get('sortby') is not None else 'lastModtime' |
|
sortby=sortby |
|
if order: |
|
order=request.args.get('order') |
|
else: |
|
order=request.cookies.get('order') if request.cookies.get('order') is not None else 'desc' |
|
order=order |
|
#参数 |
|
resp,total = FetchData(path=path,page=page,per_page=50,sortby=sortby,order=order,dismiss=True) |
|
pagination=Pagination(query=None,page=page, per_page=50, total=total, items=None) |
|
if path.split(':',1)[-1]=='/': |
|
path=':'.join([path.split(':',1)[0],'']) |
|
resp=make_response(render_template('index.html' |
|
,pagination=pagination |
|
,items=resp |
|
,path=path |
|
,image_mode=image_mode |
|
,readme=readme |
|
,ext_r=ext_r |
|
,head=head |
|
,ext_d=ext_d |
|
,sortby=sortby |
|
,order=order |
|
,cur_user=user |
|
,endpoint='.index')) |
|
resp.set_cookie('image_mode',str(image_mode)) |
|
resp.set_cookie('sortby',str(sortby)) |
|
resp.set_cookie('order',str(order)) |
|
return resp |
|
|
|
@app.route('/file/<user>/<fileid>') |
|
def show(fileid,user): |
|
name=GetName(fileid) |
|
ext=name.split('.')[-1].lower() |
|
path=GetPath(fileid) |
|
if request.method=='POST': |
|
url=request.url.replace(':80','').replace(':443','') |
|
if ext in ['csv','doc','docx','odp','ods','odt','pot','potm','potx','pps','ppsx','ppsxm','ppt','pptm','pptx','rtf','xls','xlsx']: |
|
downloadUrl=GetDownloadUrl(fileid,user) |
|
url = 'https://view.officeapps.live.com/op/view.aspx?src='+urllib.quote(downloadUrl) |
|
return redirect(url) |
|
elif ext in ['bmp','jpg','jpeg','png','gif']: |
|
return render_template('show/image.html',url=url,path=path) |
|
elif ext in ['mp4','webm']: |
|
return render_template('show/video.html',url=url,path=path) |
|
elif ext in ['mp4','webm','avi','mpg', 'mpeg', 'rm', 'rmvb', 'mov', 'wmv', 'mkv', 'asf']: |
|
return render_template('show/video2.html',url=url,path=path) |
|
elif ext in ['avi','mpg', 'mpeg', 'rm', 'rmvb', 'mov', 'wmv', 'mkv', 'asf']: |
|
return render_template('show/video2.html',url=url,path=path) |
|
elif ext in ['ogg','mp3','wav']: |
|
return render_template('show/audio.html',url=url,path=path) |
|
elif CodeType(ext) is not None: |
|
content=_remote_content(fileid,user) |
|
return render_template('show/code.html',content=content,url=url,language=CodeType(ext),path=path) |
|
else: |
|
downloadUrl=GetDownloadUrl(fileid,user) |
|
return redirect(downloadUrl) |
|
else: |
|
if 'no-referrer' in allow_site: |
|
downloadUrl=GetDownloadUrl(fileid,user) |
|
resp=redirect(downloadUrl) |
|
return resp |
|
elif sum([i in referrer for i in allow_site])>0: |
|
downloadUrl=GetDownloadUrl(fileid,user) |
|
return redirect(downloadUrl) |
|
else: |
|
return abort(404) |
|
|
|
@app.route('/robot.txt') |
|
def robot(): |
|
resp=""" |
|
User-agent: * |
|
Disallow: / |
|
""" |
|
resp=make_response(resp) |
|
resp.headers['Content-Type'] = 'text/javascript; charset=utf-8' |
|
return resp |
|
|
|
|
|
######################注册应用 |
|
from admin import admin as admin_blueprint |
|
app.register_blueprint(admin_blueprint) |
|
|
|
|
|
######################函数 |
|
app.jinja_env.globals['FetchData']=FetchData |
|
app.jinja_env.globals['path_list']=path_list |
|
app.jinja_env.globals['CanEdit']=CanEdit |
|
app.jinja_env.globals['len']=len |
|
app.jinja_env.globals['enumerate']=enumerate |
|
app.jinja_env.globals['os']=os |
|
app.jinja_env.globals['re']=re |
|
app.jinja_env.globals['file_ico']=file_ico |
|
app.jinja_env.globals['title']=title |
|
app.jinja_env.globals['tj_code']=tj_code if tj_code is not None else '' |
|
app.jinja_env.globals['get_od_user']=get_od_user |
|
app.jinja_env.globals['allow_site']=','.join(allow_site) |
|
# app.jinja_env.globals['share_path']=od_users.get('A').get('share_path') |
|
app.jinja_env.globals['downloadUrl_timeout']=downloadUrl_timeout |
|
################################################################################ |
|
#####################################启动####################################### |
|
################################################################################ |
|
if __name__=='__main__': |
|
app.run(port=58693,debug=True) |
|
|
|
|
|
|
|
|