Skip to content

Commit 19806f0

Browse files
author
lan-air
committed
Init
0 parents  commit 19806f0

File tree

9 files changed

+747
-0
lines changed

9 files changed

+747
-0
lines changed

.gitignore

Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
1+
media/
2+
logs/
3+
.idea
4+
static/
5+
__pycache__/
6+
*.py[cod]
7+
*$py.class
8+
# Created by .ignore support plugin (hsz.mobi)
9+
### Python template
10+
# Byte-compiled / optimized / DLL files
11+
12+
# C extensions
13+
*.so
14+
*.env
15+
# Distribution / packaging
16+
.Python
17+
build/
18+
develop-eggs/
19+
dist/
20+
downloads/
21+
eggs/
22+
.eggs/
23+
lib/
24+
lib64/
25+
parts/
26+
sdist/
27+
var/
28+
wheels/
29+
share/python-wheels/
30+
*.egg-info/
31+
.installed.cfg
32+
*.egg
33+
MANIFEST
34+
35+
# PyInstaller
36+
# Usually these files are written by a python script from a template
37+
# before PyInstaller builds the exe, so as to inject date/other infos into it.
38+
*.manifest
39+
*.spec
40+
41+
# Installer logs
42+
pip-log.txt
43+
pip-delete-this-directory.txt
44+
45+
# Unit test.pdf / coverage reports
46+
htmlcov/
47+
.tox/
48+
.nox/
49+
.coverage
50+
.coverage.*
51+
.cache
52+
nosetests.xml
53+
coverage.xml
54+
*.cover
55+
*.py,cover
56+
.hypothesis/
57+
.pytest_cache/
58+
cover/
59+
60+
# Translations
61+
*.mo
62+
*.pot
63+
64+
# Django stuff:
65+
*.log
66+
local_settings.py
67+
db.sqlite3
68+
db.sqlite3-journal
69+
70+
# Flask stuff:
71+
instance/
72+
.webassets-cache
73+
74+
# Scrapy stuff:
75+
.scrapy
76+
77+
# Sphinx documentation
78+
docs/_build/
79+
80+
# PyBuilder
81+
.pybuilder/
82+
target/
83+
84+
# Jupyter Notebook
85+
.ipynb_checkpoints
86+
87+
# IPython
88+
profile_default/
89+
ipython_config.py
90+
91+
# pyenv
92+
# For a library or package, you might want to ignore these files since the code is
93+
# intended to run in multiple environments; otherwise, check them in:
94+
# .python-version
95+
96+
# pipenv
97+
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
98+
# However, in case of collaboration, if having platform-specific dependencies or dependencies
99+
# having no cross-platform support, pipenv may install dependencies that don't work, or not
100+
# install all needed dependencies.
101+
#Pipfile.lock
102+
103+
# PEP 582; used by e.g. github.com/David-OConnor/pyflow
104+
__pypackages__/
105+
106+
# Celery stuff
107+
celerybeat-schedule
108+
celerybeat.pid
109+
110+
# SageMath parsed files
111+
*.sage.py
112+
113+
# Environments
114+
.env
115+
.venv
116+
env/
117+
venv/
118+
ENV/
119+
env.bak/
120+
venv.bak/
121+
122+
# Spyder project settings
123+
.spyderproject
124+
.spyproject
125+
126+
# Rope project settings
127+
.ropeproject
128+
129+
# mkdocs documentation
130+
/site
131+
132+
# mypy
133+
.mypy_cache/
134+
.dmypy.json
135+
dmypy.json
136+
137+
# Pyre type checker
138+
.pyre/
139+
140+
# pytype static type analyzer
141+
.pytype/
142+
143+
# Cython debug symbols
144+
cython_debug/
145+
146+
# Project
147+
.vscode
148+
.DS_Store
149+
for_test.py
150+
.html
151+
/evaluate/temp.py
152+
/evaluation/back.json
153+
.env*
154+
.backup/
155+
/cloc-1.64.exe
156+
*.db

Dockerfile

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
FROM python:3.9.5
2+
LABEL author="Lan"
3+
LABEL email="[email protected]"
4+
LABEL version="1.0"
5+
6+
7+
COPY . /app
8+
RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
9+
RUN echo 'Asia/Shanghai' >/etc/timezone
10+
WORKDIR /app
11+
RUN pip install -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple/
12+
EXPOSE 123456
13+
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "12345"]

database.db

20 KB
Binary file not shown.

database.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import datetime
2+
3+
from sqlalchemy import create_engine, DateTime
4+
from sqlalchemy.orm import sessionmaker
5+
from sqlalchemy.ext.declarative import declarative_base
6+
from sqlalchemy import Boolean, Column, Integer, String
7+
8+
engine = create_engine('sqlite:///database.db', connect_args={"check_same_thread": False})
9+
Base = declarative_base()
10+
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
11+
12+
13+
class Codes(Base):
14+
__tablename__ = 'codes'
15+
id = Column(Integer, primary_key=True, index=True)
16+
code = Column(String(10), unique=True, index=True)
17+
key = Column(String(30), unique=True, index=True)
18+
name = Column(String(500))
19+
size = Column(Integer)
20+
type = Column(String(20))
21+
text = Column(String(500))
22+
used = Column(Boolean, default=False)
23+
use_time = Column(DateTime, default=datetime.datetime.now, onupdate=datetime.datetime.now)

main.py

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
import datetime
2+
import os
3+
import uuid
4+
5+
from fastapi import FastAPI, Depends, UploadFile, Form, File
6+
from sqlalchemy.orm import Session
7+
from starlette.requests import Request
8+
from starlette.responses import HTMLResponse
9+
import random
10+
11+
from starlette.staticfiles import StaticFiles
12+
13+
import database
14+
from database import engine, SessionLocal, Base
15+
16+
Base.metadata.create_all(bind=engine)
17+
app = FastAPI()
18+
if not os.path.exists('./static'):
19+
os.makedirs('./static')
20+
app.mount("/static", StaticFiles(directory="static"), name="static")
21+
# 过期时间
22+
exp_hour = 24
23+
# 允许错误次数
24+
error_count = 5
25+
# 禁止分钟数
26+
error_minute = 60
27+
28+
error_ip_count = {}
29+
30+
31+
def get_db():
32+
db = SessionLocal()
33+
try:
34+
yield db
35+
finally:
36+
db.close()
37+
38+
39+
def get_code(db: Session = Depends(get_db)):
40+
code = random.randint(10000, 99999)
41+
while db.query(database.Codes).filter(database.Codes.code == code).first():
42+
code = random.randint(10000, 99999)
43+
return str(code)
44+
45+
46+
def get_file_name(key, ext, file):
47+
now = datetime.datetime.now()
48+
path = f'./static/upload/{now.year}/{now.month}/{now.day}/'
49+
name = f'{key}.{ext}'
50+
if not os.path.exists(path):
51+
os.makedirs(path)
52+
file = file.file.read()
53+
with open(f'{os.path.join(path, name)}', 'wb') as f:
54+
f.write(file)
55+
return key, len(file), path[1:] + name
56+
57+
58+
@app.get('/')
59+
async def index():
60+
with open('templates/index.html', 'r') as f:
61+
return HTMLResponse(f.read())
62+
63+
64+
@app.post('/')
65+
async def index(request: Request, code: str, db: Session = Depends(get_db)):
66+
info = db.query(database.Codes).filter(database.Codes.code == code).first()
67+
error = error_ip_count.get(request.client.host, {'count': 0, 'time': datetime.datetime.now()})
68+
if error['count'] > error_count:
69+
if datetime.datetime.now() - error['time'] < datetime.timedelta(minutes=error_minute):
70+
return {'code': 404, 'msg': '请求过于频繁,请稍后再试'}
71+
else:
72+
error['count'] = 0
73+
else:
74+
if not info:
75+
error['count'] += 1
76+
error_ip_count[request.client.host] = error
77+
return {'code': 404, 'msg': f'取件码错误,错误5次将被禁止10分钟'}
78+
else:
79+
return {'code': 200, 'msg': '取件成功,请点击库查看', 'data': info}
80+
81+
82+
@app.get('/share')
83+
async def share():
84+
with open('templates/upload.html', 'r') as f:
85+
return HTMLResponse(f.read())
86+
87+
88+
@app.post('/share')
89+
async def share(text: str = Form(default=None), file: UploadFile = File(default=None), db: Session = Depends(get_db)):
90+
cutoff_time = datetime.datetime.now() - datetime.timedelta(hours=exp_hour)
91+
db.query(database.Codes).filter(database.Codes.use_time < cutoff_time).delete()
92+
db.commit()
93+
code = get_code(db)
94+
if text:
95+
info = database.Codes(
96+
code=code,
97+
text=text,
98+
type='text/plain',
99+
key=uuid.uuid4().hex,
100+
size=len(text),
101+
used=True,
102+
name='分享文本'
103+
)
104+
db.add(info)
105+
db.commit()
106+
return {'code': 200, 'msg': '上传成功,请点击文件库查看',
107+
'data': {'code': code, 'name': '分享文本', 'text': text}}
108+
elif file:
109+
key, size, full_path = get_file_name(uuid.uuid4().hex, file.filename.split('.')[-1], file)
110+
info = database.Codes(
111+
code=code,
112+
text=full_path,
113+
type=file.content_type,
114+
key=key,
115+
size=size,
116+
used=True,
117+
name=file.filename
118+
)
119+
db.add(info)
120+
db.commit()
121+
return {'code': 200, 'msg': '上传成功,请点击文件库查看',
122+
'data': {'code': code, 'name': file.filename, 'text': full_path}}
123+
else:
124+
return {'code': 422, 'msg': '参数错误', 'data': []}

readme.md

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
# 口令传送箱
2+
3+
## 主要特色
4+
5+
- [x] 拖拽,复制粘贴上传
6+
- [x] 文件口令传输
7+
- [x] 分享文件:多种上传方式供你选择
8+
- [x] 分享文本:直接复制粘贴直接上传
9+
- [x] 防爆破:错误五次拉黑十分钟
10+
- [x] 完全匿名:不记录任何信息
11+
- [x] 无需注册:无需注册,无需登录
12+
- [x] Sqlite3数据库:无需安装数据库
13+
14+
## 部署方式
15+
16+
### 服务端部署
17+
18+
1. 安装Python3
19+
2. 拉取代码,解压缩
20+
3. 安装依赖包:`pip install -r requirements.txt`
21+
4. 运行` uvicorn main:app --host 0.0.0.0 --port 12345`
22+
5. 然后你自己看怎么进程守护吧
23+
24+
### 宝塔部署
25+
26+
1. 安装宝塔Python Manager
27+
2. 然后你自己看着填吧
28+
29+
### Docker部署
30+
31+
```bash
32+
docker build --file Dockerfile --tag filecodebox .
33+
docker run -d -p 12345:12345 --name filecodebox filecodebox
34+
```

requirements.txt

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
anyio==3.6.2
2+
click==8.1.3
3+
fastapi==0.88.0
4+
h11==0.14.0
5+
httptools==0.5.0
6+
idna==3.4
7+
pydantic==1.10.2
8+
python-dotenv==0.21.0
9+
python-multipart==0.0.5
10+
PyYAML==6.0
11+
six==1.16.0
12+
sniffio==1.3.0
13+
SQLAlchemy==1.4.44
14+
starlette==0.22.0
15+
typing_extensions==4.4.0
16+
uvicorn==0.20.0
17+
uvloop==0.17.0
18+
watchfiles==0.18.1
19+
websockets==10.4

0 commit comments

Comments
 (0)