diff --git a/images/img_3.png b/images/img_3.png index c9c6a8a..b14a1df 100644 Binary files a/images/img_3.png and b/images/img_3.png differ diff --git a/main.py b/main.py index d4c6688..0921a1b 100644 --- a/main.py +++ b/main.py @@ -18,24 +18,43 @@ app = FastAPI() if not os.path.exists('./static'): os.makedirs('./static') app.mount("/static", StaticFiles(directory="static"), name="static") -index_html = open('templates/index.html', 'r', encoding='utf-8').read() -admin_html = open('templates/admin.html', 'r', encoding='utf-8').read() -# 过期时间 -exp_hour = 24 + +############################################ +# 需要修改的参数 # 允许错误次数 error_count = 5 # 禁止分钟数 -error_minute = 60 +error_minute = 10 # 后台地址 admin_address = 'admin' # 管理密码 admin_password = 'admin' +# 文件大小限制 10M +file_size_limit = 1024 * 1024 * 10 +# 系统标题 +title = '口令传送箱' +# 系统描述 +description = 'FileCodeBox,口令传送箱,匿名口令分享文本,文件,图片,视频,音频,压缩包等文件' +# 系统关键字 +keywords = 'FileCodeBox,口令传送箱,匿名口令分享文本,文件,图片,视频,音频,压缩包等文件' +############################################ + +index_html = open('templates/index.html', 'r', encoding='utf-8').read() \ + .replace('{{title}}', title) \ + .replace('{{description}}', description) \ + .replace('{{keywords}}', keywords) +admin_html = open('templates/admin.html', 'r', encoding='utf-8').read() \ + .replace('{{title}}', title) \ + .replace('{{description}}', description) \ + .replace('{{keywords}}', keywords) + error_ip_count = {} def delete_file(files): for file in files: - os.remove('.' + file) + if file['type'] != 'text': + os.remove('.' + file['text']) def get_db(): @@ -55,14 +74,17 @@ def get_code(db: Session = Depends(get_db)): def get_file_name(key, ext, file): now = datetime.datetime.now() + file_bytes = file.file.read() + size = len(file_bytes) + if size > file_size_limit: + return size, '', '', '' path = f'./static/upload/{now.year}/{now.month}/{now.day}/' name = f'{key}.{ext}' if not os.path.exists(path): os.makedirs(path) - file = file.file.read() with open(f'{os.path.join(path, name)}', 'wb') as f: - f.write(file) - return key, len(file), path[1:] + name + f.write(file_bytes) + return size, path[1:] + name, file.content_type, file.filename @app.get(f'/{admin_address}') @@ -76,20 +98,19 @@ async def admin_post(request: Request, db: Session = Depends(get_db)): codes = db.query(database.Codes).all() return {'code': 200, 'msg': '查询成功', 'data': codes} else: - return {'code': 400, 'msg': '密码错误'} + return {'code': 404, 'msg': '密码错误'} @app.delete(f'/{admin_address}') async def admin_delete(request: Request, code: str, db: Session = Depends(get_db)): if request.headers.get('pwd') == admin_password: - file = db.query(database.Codes).filter(database.Codes.code == code) - if file.first().type != 'text/plain': - threading.Thread(target=delete_file, args=([file.first().text],)).start() - file.delete() + file = db.query(database.Codes).filter(database.Codes.code == code).first() + threading.Thread(target=delete_file, args=([{'type': file.type, 'text': file.text}],)).start() + db.delete(file) db.commit() return {'code': 200, 'msg': '删除成功'} else: - return {'code': 400, 'msg': '密码错误'} + return {'code': 404, 'msg': '密码错误'} @app.get('/') @@ -97,60 +118,87 @@ async def index(): return HTMLResponse(index_html) +def check_ip(ip): + # 检查ip是否被禁止 + if ip in error_ip_count: + if error_ip_count[ip]['count'] >= error_count: + if error_ip_count[ip]['time'] + datetime.timedelta(minutes=error_minute) > datetime.datetime.now(): + return False + else: + error_ip_count.pop(ip) + return True + + +def ip_error(ip): + ip_info = error_ip_count.get(ip, {'count': 0, 'time': datetime.datetime.now()}) + ip_info['count'] += 1 + error_ip_count[ip] = ip_info + return ip_info['count'] + + @app.post('/') async def index(request: Request, code: str, db: Session = Depends(get_db)): + ip = request.client.host + if not check_ip(ip): + return {'code': 404, 'msg': '错误次数过多,请稍后再试'} info = db.query(database.Codes).filter(database.Codes.code == code).first() - error = error_ip_count.get(request.client.host, {'count': 0, 'time': datetime.datetime.now()}) - if error['count'] > error_count: - if datetime.datetime.now() - error['time'] < datetime.timedelta(minutes=error_minute): - return {'code': 404, 'msg': '请求过于频繁,请稍后再试'} - else: - error['count'] = 0 - else: - if not info: - error['count'] += 1 - error_ip_count[request.client.host] = error - return {'code': 404, 'msg': f'取件码错误,错误5次将被禁止10分钟'} - else: - return {'code': 200, 'msg': '取件成功,请点击“取”查看', 'data': info} + if not info: + return {'code': 404, 'msg': f'取件码错误,错误{error_count - ip_error(ip)}次将被禁止10分钟'} + if info.exp_time < datetime.datetime.now(): + threading.Thread(target=delete_file, args=([{'type': info.type, 'text': info.text}],)).start() + db.delete(info) + db.commit() + return {'code': 404, 'msg': '取件码已过期,请联系寄件人'} + info.count -= 1 + if info.count == 0: + threading.Thread(target=delete_file, args=([{'type': info.type, 'text': info.text}],)).start() + db.delete(info) + db.commit() + return {'code': 200, 'msg': '取件成功,请点击"取"查看', 'data': info} @app.post('/share') -async def share(text: str = Form(default=None), file: UploadFile = File(default=None), db: Session = Depends(get_db)): - cutoff_time = datetime.datetime.now() - datetime.timedelta(hours=exp_hour) - olds = db.query(database.Codes).filter(database.Codes.use_time < cutoff_time) - threading.Thread(target=delete_file, args=([old.text for old in olds if old.type != 'text/plain'],)).start() - olds.delete() +async def share(text: str = Form(default=None), style: str = Form(default='2'), value: int = Form(default=1), + file: UploadFile = File(default=None), db: Session = Depends(get_db)): + exps = db.query(database.Codes).filter(database.Codes.exp_time < datetime.datetime.now()) + threading.Thread(target=delete_file, args=([[{'type': old.type, 'text': old.text}] for old in exps.all()],)).start() + exps.delete() db.commit() code = get_code(db) - if text: - info = database.Codes( - code=code, - text=text, - type='text/plain', - key=uuid.uuid4().hex, - size=len(text), - used=True, - name='分享文本' - ) - db.add(info) - db.commit() - return {'code': 200, 'msg': '上传成功,请点击文件库查看', - 'data': {'code': code, 'name': '分享文本', 'text': text}} - elif file: - key, size, full_path = get_file_name(uuid.uuid4().hex, file.filename.split('.')[-1], file) - info = database.Codes( - code=code, - text=full_path, - type=file.content_type, - key=key, - size=size, - used=True, - name=file.filename - ) - db.add(info) - db.commit() - return {'code': 200, 'msg': '上传成功,请点击文件库查看', - 'data': {'code': code, 'name': file.filename, 'text': full_path}} + if style == '2': + if value > 7: + return {'code': 404, 'msg': '最大有效天数为7天'} + exp_time = datetime.datetime.now() + datetime.timedelta(days=value) + exp_count = -1 + elif style == '1': + if value < 1: + return {'code': 404, 'msg': '最小有效次数为1次'} + exp_time = datetime.datetime.now() + datetime.timedelta(days=1) + exp_count = value else: - return {'code': 422, 'msg': '参数错误', 'data': []} + exp_time = datetime.datetime.now() + datetime.timedelta(days=1) + exp_count = -1 + key = uuid.uuid4().hex + if file: + size, _text, _type, name = get_file_name(key, file.filename.split('.')[-1], file) + if size > file_size_limit: + return {'code': 404, 'msg': '文件过大'} + else: + size, _text, _type, name = len(text), text, 'text', '文本分享' + info = database.Codes( + code=code, + text=_text, + size=size, + type=_type, + name=name, + count=exp_count, + exp_time=exp_time, + key=key + ) + db.add(info) + db.commit() + return { + 'code': 200, + 'msg': '分享成功,请点击文件箱查看取件码', + 'data': {'code': code, 'key': key, 'name': name, 'text': _text} + } diff --git a/readme.md b/readme.md index 768565b..72e0c0e 100644 --- a/readme.md +++ b/readme.md @@ -17,7 +17,7 @@ - [x] Sqlite3数据库:无需安装数据库 - [x] 可以加get参数code,这样打开就会读取取件码如:http://xxx.com?code=12345 - [x] 管理面板:简单列表页删除违规文件 -- [ ] 口令使用次数,口令有效期,二维码分享 +- [x] 口令使用次数,口令有效期,二维码分享 ## 更新记录 @@ -26,6 +26,13 @@ 1. 管理面板已新增,一如既往的极简,只有删除 2. 二维码图片(调用的网络接口,如果离线环境将无法使用,一切为了极简) +### 2022年12月10日 21:10:00 + +1. 取件码有效期,取件码使用次数 +2. 优化代码逻辑 +3. 限制上传文件大小 +4. 完善配置参数 + ## 系统截图 ### 取件 diff --git a/templates/admin.html b/templates/admin.html index f98941a..7c885bb 100644 --- a/templates/admin.html +++ b/templates/admin.html @@ -6,13 +6,19 @@ content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"> - 后台管理-口令传送箱 + 后台管理-{{title}} + + + +
- -   - + + +   + + @@ -21,6 +27,8 @@
取件码:${ file.code }
文件名:${ file.name }
+
次   数:${ file.count }
+
到   期:${ file.exp_time.slice(0,19) }
内   容:${ file.text }
@@ -39,7 +47,7 @@ -   +  
@@ -60,7 +68,12 @@ return { login: false, pwd: '', - files: [] + files: [], + config: { + error_count: 0, + file_size: 0, + admin_pwd: 'admin' + } }; }, mounted: function () { @@ -97,7 +110,7 @@ }); } }) - } + }, } }) diff --git a/templates/index.html b/templates/index.html index 869b569..740c793 100644 --- a/templates/index.html +++ b/templates/index.html @@ -6,8 +6,11 @@ content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"> - - 口令传送箱 + {{title}} + + + +