Merge branch 'master' into boop

This commit is contained in:
Siina Mashek 2023-06-04 09:02:13 +03:00
commit 7d7bcd045e
3 changed files with 53 additions and 10 deletions

View file

@ -107,6 +107,7 @@ db = SQLAlchemy(app)
migrate = Migrate(app, db) migrate = Migrate(app, db)
class URL(db.Model): class URL(db.Model):
__tablename__ = "URL"
id = db.Column(db.Integer, primary_key = True) id = db.Column(db.Integer, primary_key = True)
url = db.Column(db.UnicodeText, unique = True) url = db.Column(db.UnicodeText, unique = True)
@ -135,6 +136,7 @@ class File(db.Model):
ext = db.Column(db.UnicodeText) ext = db.Column(db.UnicodeText)
mime = db.Column(db.UnicodeText) mime = db.Column(db.UnicodeText)
addr = db.Column(db.UnicodeText) addr = db.Column(db.UnicodeText)
ua = db.Column(db.UnicodeText)
removed = db.Column(db.Boolean, default=False) removed = db.Column(db.Boolean, default=False)
nsfw_score = db.Column(db.Float) nsfw_score = db.Column(db.Float)
expiration = db.Column(db.BigInteger) expiration = db.Column(db.BigInteger)
@ -143,11 +145,12 @@ class File(db.Model):
last_vscan = db.Column(db.DateTime) last_vscan = db.Column(db.DateTime)
size = db.Column(db.BigInteger) size = db.Column(db.BigInteger)
def __init__(self, sha256, ext, mime, addr, expiration, mgmt_token): def __init__(self, sha256, ext, mime, addr, ua, expiration, mgmt_token):
self.sha256 = sha256 self.sha256 = sha256
self.ext = ext self.ext = ext
self.mime = mime self.mime = mime
self.addr = addr self.addr = addr
self.ua = ua
self.expiration = expiration self.expiration = expiration
self.mgmt_token = mgmt_token self.mgmt_token = mgmt_token
@ -212,7 +215,7 @@ class File(db.Model):
Any value greater that the longest allowed file lifespan will be rounded down to that Any value greater that the longest allowed file lifespan will be rounded down to that
value. value.
""" """
def store(file_, requested_expiration: typing.Optional[int], addr, secret: bool): def store(file_, requested_expiration: typing.Optional[int], addr, ua, secret: bool):
data = file_.read() data = file_.read()
digest = sha256(data).hexdigest() digest = sha256(data).hexdigest()
@ -248,8 +251,10 @@ class File(db.Model):
if not ext: if not ext:
if gmime in app.config["FHOST_EXT_OVERRIDE"]: if gmime in app.config["FHOST_EXT_OVERRIDE"]:
ext = app.config["FHOST_EXT_OVERRIDE"][gmime] ext = app.config["FHOST_EXT_OVERRIDE"][gmime]
elif guess:
ext = guess
else: else:
ext = guess_extension(gmime) ext = ""
return ext[:app.config["FHOST_MAX_EXT_LENGTH"]] or ".bin" return ext[:app.config["FHOST_MAX_EXT_LENGTH"]] or ".bin"
@ -276,9 +281,10 @@ class File(db.Model):
mime = get_mime() mime = get_mime()
ext = get_ext(mime) ext = get_ext(mime)
mgmt_token = secrets.token_urlsafe() mgmt_token = secrets.token_urlsafe()
f = File(digest, ext, mime, addr, expiration, mgmt_token) f = File(digest, ext, mime, addr, ua, expiration, mgmt_token)
f.addr = addr f.addr = addr
f.ua = ua
if isnew: if isnew:
f.secret = None f.secret = None
@ -366,11 +372,11 @@ requested_expiration can be:
Any value greater that the longest allowed file lifespan will be rounded down to that Any value greater that the longest allowed file lifespan will be rounded down to that
value. value.
""" """
def store_file(f, requested_expiration: typing.Optional[int], addr, secret: bool): def store_file(f, requested_expiration: typing.Optional[int], addr, ua, secret: bool):
if in_upload_bl(addr): if in_upload_bl(addr):
return "Your host is blocked from uploading files.\n", 451 return "Your host is blocked from uploading files.\n", 451
sf, isnew = File.store(f, requested_expiration, addr, secret) sf, isnew = File.store(f, requested_expiration, addr, ua, secret)
response = make_response(sf.geturl()) response = make_response(sf.geturl())
response.headers["X-Expires"] = sf.expiration response.headers["X-Expires"] = sf.expiration
@ -380,7 +386,7 @@ def store_file(f, requested_expiration: typing.Optional[int], addr, secret: boo
return response return response
def store_url(url, addr, secret: bool): def store_url(url, addr, ua, secret: bool):
if is_fhost_url(url): if is_fhost_url(url):
abort(400) abort(400)
@ -395,13 +401,13 @@ def store_url(url, addr, secret: bool):
if "content-length" in r.headers: if "content-length" in r.headers:
l = int(r.headers["content-length"]) l = int(r.headers["content-length"])
if l < app.config["MAX_CONTENT_LENGTH"]: if l <= app.config["MAX_CONTENT_LENGTH"]:
def urlfile(**kwargs): def urlfile(**kwargs):
return type('',(),kwargs)() return type('',(),kwargs)()
f = urlfile(read=r.raw.read, content_type=r.headers["content-type"], filename="") f = urlfile(read=r.raw.read, content_type=r.headers["content-type"], filename="")
return store_file(f, None, addr, secret) return store_file(f, None, addr, ua, secret)
else: else:
abort(413) abort(413)
else: else:
@ -496,6 +502,7 @@ def fhost():
request.files["file"], request.files["file"],
int(request.form["expires"]), int(request.form["expires"]),
request.remote_addr, request.remote_addr,
request.user_agent.string,
secret secret
) )
except ValueError: except ValueError:
@ -507,12 +514,14 @@ def fhost():
request.files["file"], request.files["file"],
None, None,
request.remote_addr, request.remote_addr,
request.user_agent.string,
secret secret
) )
elif "url" in request.form: elif "url" in request.form:
return store_url( return store_url(
request.form["url"], request.form["url"],
request.remote_addr, request.remote_addr,
request.user_agent.string,
secret secret
) )
elif "shorten" in request.form: elif "shorten" in request.form:

View file

@ -0,0 +1,30 @@
"""Store user agent string with files
Revision ID: dd0766afb7d2
Revises: 30bfe33aa328
Create Date: 2023-03-29 07:18:49.113200
"""
# revision identifiers, used by Alembic.
revision = 'dd0766afb7d2'
down_revision = '30bfe33aa328'
from alembic import op
import sqlalchemy as sa
def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
with op.batch_alter_table('file', schema=None) as batch_op:
batch_op.add_column(sa.Column('ua', sa.UnicodeText(), nullable=True))
# ### end Alembic commands ###
def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
with op.batch_alter_table('file', schema=None) as batch_op:
batch_op.drop_column('ua')
# ### end Alembic commands ###

6
mod.py
View file

@ -26,6 +26,7 @@ class NullptrMod(Screen):
("f4", "filter(4, 'Filter extension:')", "Filter Ext."), ("f4", "filter(4, 'Filter extension:')", "Filter Ext."),
("f5", "refresh", "Refresh"), ("f5", "refresh", "Refresh"),
("f6", "filter_clear", "Clear filter"), ("f6", "filter_clear", "Clear filter"),
("f7", "filter(5, 'Filter user agent:')", "Filter UA"),
("r", "remove_file(False)", "Remove file"), ("r", "remove_file(False)", "Remove file"),
("ctrl+r", "remove_file(True)", "Ban file"), ("ctrl+r", "remove_file(True)", "Ban file"),
("p", "ban_ip(False)", "Ban IP"), ("p", "ban_ip(False)", "Ban IP"),
@ -60,6 +61,7 @@ class NullptrMod(Screen):
case 2: finput.value = self.current_file.addr case 2: finput.value = self.current_file.addr
case 3: finput.value = self.current_file.mime case 3: finput.value = self.current_file.mime
case 4: finput.value = self.current_file.ext case 4: finput.value = self.current_file.ext
case 5: finput.value = self.current_file.ua or ""
def on_input_submitted(self, message: Input.Submitted) -> None: def on_input_submitted(self, message: Input.Submitted) -> None:
self.query_one("#filter_container").display = False self.query_one("#filter_container").display = False
@ -71,9 +73,10 @@ class NullptrMod(Screen):
case 1: case 1:
try: ftable.query = ftable.base_query.filter(File.id == su.debase(message.value)) try: ftable.query = ftable.base_query.filter(File.id == su.debase(message.value))
except ValueError: pass except ValueError: pass
case 2: ftable.query = ftable.base_query.filter(File.addr == message.value) case 2: ftable.query = ftable.base_query.filter(File.addr.like(message.value))
case 3: ftable.query = ftable.base_query.filter(File.mime.like(message.value)) case 3: ftable.query = ftable.base_query.filter(File.mime.like(message.value))
case 4: ftable.query = ftable.base_query.filter(File.ext.like(message.value)) case 4: ftable.query = ftable.base_query.filter(File.ext.like(message.value))
case 5: ftable.query = ftable.base_query.filter(File.ua.like(message.value))
else: else:
ftable.query = ftable.base_query ftable.query = ftable.base_query
@ -249,6 +252,7 @@ class NullptrMod(Screen):
("MIME type:", f.mime), ("MIME type:", f.mime),
("SHA256 checksum:", f.sha256), ("SHA256 checksum:", f.sha256),
("Uploaded by:", Text(f.addr)), ("Uploaded by:", Text(f.addr)),
("User agent:", Text(f.ua or "")),
("Management token:", f.mgmt_token), ("Management token:", f.mgmt_token),
("Secret:", f.secret), ("Secret:", f.secret),
("Is NSFW:", ("Yes" if f.is_nsfw else "No") + (f" (Score: {f.nsfw_score:0.4f})" if f.nsfw_score else " (Not scanned)")), ("Is NSFW:", ("Yes" if f.is_nsfw else "No") + (f" (Score: {f.nsfw_score:0.4f})" if f.nsfw_score else " (Not scanned)")),