mirror of
https://gitlab.com/SIGBUS/nyaa.git
synced 2024-12-22 08:40:00 +00:00
Add (optional) validation for minimum anonymous torrent size (#342)
MINIMUM_ANONYMOUS_TORRENT_SIZE can be used to require a minimum total size of torrents uploaded by anonymous users (ie. without accounts). Sets up a "framework" for post-WTForm torrent validation as well; this can easily be extended into filename blacklists and such.
This commit is contained in:
parent
48d4217f02
commit
39fcfc0058
|
@ -46,6 +46,9 @@ ENFORCE_MAIN_ANNOUNCE_URL = False
|
|||
MAIN_ANNOUNCE_URL = 'http://127.0.0.1:6881/announce'
|
||||
TRACKER_API_URL = 'http://127.0.0.1:6881/api'
|
||||
TRACKER_API_AUTH = 'topsecret'
|
||||
# Torrents uploaded without an account must be at least this big in total (bytes)
|
||||
# Set to 0 to disable
|
||||
MINIMUM_ANONYMOUS_TORRENT_SIZE = 1 * 1024 * 1024
|
||||
|
||||
BACKUP_TORRENT_FOLDER = 'torrents'
|
||||
|
||||
|
|
|
@ -99,22 +99,25 @@ def v2_api_upload():
|
|||
upload_form.category.choices = _create_upload_category_choices()
|
||||
|
||||
if upload_form.validate():
|
||||
torrent = backend.handle_torrent_upload(upload_form, flask.g.user)
|
||||
try:
|
||||
torrent = backend.handle_torrent_upload(upload_form, flask.g.user)
|
||||
|
||||
# Create a response dict with relevant data
|
||||
torrent_metadata = {
|
||||
'url': flask.url_for('torrents.view', torrent_id=torrent.id, _external=True),
|
||||
'id': torrent.id,
|
||||
'name': torrent.display_name,
|
||||
'hash': torrent.info_hash.hex(),
|
||||
'magnet': torrent.magnet_uri
|
||||
}
|
||||
# Create a response dict with relevant data
|
||||
torrent_metadata = {
|
||||
'url': flask.url_for('torrents.view', torrent_id=torrent.id, _external=True),
|
||||
'id': torrent.id,
|
||||
'name': torrent.display_name,
|
||||
'hash': torrent.info_hash.hex(),
|
||||
'magnet': torrent.magnet_uri
|
||||
}
|
||||
|
||||
return flask.jsonify(torrent_metadata)
|
||||
else:
|
||||
# Map errors back from form fields into the api keys
|
||||
mapped_errors = {UPLOAD_API_FORM_KEYMAP.get(k, k): v for k, v in upload_form.errors.items()}
|
||||
return flask.jsonify({'errors': mapped_errors}), 400
|
||||
return flask.jsonify(torrent_metadata)
|
||||
except backend.TorrentExtraValidationException:
|
||||
pass
|
||||
|
||||
# Map errors back from form fields into the api keys
|
||||
mapped_errors = {UPLOAD_API_FORM_KEYMAP.get(k, k): v for k, v in upload_form.errors.items()}
|
||||
return flask.jsonify({'errors': mapped_errors}), 400
|
||||
|
||||
|
||||
# #################################### TEMPORARY ####################################
|
||||
|
|
|
@ -15,6 +15,11 @@ from nyaa.extensions import db
|
|||
app = flask.current_app
|
||||
|
||||
|
||||
class TorrentExtraValidationException(Exception):
|
||||
def __init__(self, errors):
|
||||
self.errors = errors
|
||||
|
||||
|
||||
@utils.cached_function
|
||||
def get_category_id_map():
|
||||
''' Reads database for categories and turns them into a dict with
|
||||
|
@ -44,7 +49,37 @@ def _replace_utf8_values(dict_or_list):
|
|||
return did_change
|
||||
|
||||
|
||||
def validate_torrent_post_upload(torrent, upload_form=None):
|
||||
''' Validates a Torrent instance before it's saved to the database.
|
||||
Enforcing user-and-such-based validations is more flexible here vs WTForm context '''
|
||||
errors = {
|
||||
'torrent_file': []
|
||||
}
|
||||
|
||||
# Encorce minimum size for userless uploads
|
||||
minimum_anonymous_torrent_size = app.config['MINIMUM_ANONYMOUS_TORRENT_SIZE']
|
||||
if torrent.user is None and torrent.filesize < minimum_anonymous_torrent_size:
|
||||
errors['torrent_file'].append('Torrent too small for an anonymous uploader')
|
||||
|
||||
print(errors)
|
||||
# Remove keys with empty lists
|
||||
errors = {k: v for k, v in errors.items() if v}
|
||||
if errors:
|
||||
if upload_form:
|
||||
# Add error messages to the form fields
|
||||
for field_name, field_errors in errors.items():
|
||||
getattr(upload_form, field_name).errors.extend(field_errors)
|
||||
# Clear out the wtforms dict to force a regeneration
|
||||
upload_form._errors = None
|
||||
|
||||
raise TorrentExtraValidationException(errors)
|
||||
|
||||
|
||||
def handle_torrent_upload(upload_form, uploading_user=None, fromAPI=False):
|
||||
''' Stores a torrent to the database.
|
||||
May throw TorrentExtraValidationException if the form/torrent fails
|
||||
post-WTForm validation! Exception messages will also be added to their
|
||||
relevant fields on the given form. '''
|
||||
torrent_data = upload_form.torrent_file.parsed_data
|
||||
|
||||
# Delete exisiting torrent which is marked as deleted
|
||||
|
@ -197,6 +232,9 @@ def handle_torrent_upload(upload_form, uploading_user=None, fromAPI=False):
|
|||
tracker_id=tracker.id, order=order)
|
||||
db.session.add(torrent_tracker)
|
||||
|
||||
# Before final commit, validate the torrent again
|
||||
validate_torrent_post_upload(torrent, upload_form)
|
||||
|
||||
db.session.commit()
|
||||
|
||||
# Store the actual torrent file as well
|
||||
|
|
|
@ -307,13 +307,16 @@ def upload():
|
|||
upload_form.category.choices = _create_upload_category_choices()
|
||||
|
||||
if flask.request.method == 'POST' and upload_form.validate():
|
||||
torrent = backend.handle_torrent_upload(upload_form, flask.g.user)
|
||||
try:
|
||||
torrent = backend.handle_torrent_upload(upload_form, flask.g.user)
|
||||
|
||||
return flask.redirect(flask.url_for('torrents.view', torrent_id=torrent.id))
|
||||
else:
|
||||
# If we get here with a POST, it means the form data was invalid: return a non-okay status
|
||||
status_code = 400 if flask.request.method == 'POST' else 200
|
||||
return flask.render_template('upload.html', upload_form=upload_form), status_code
|
||||
return flask.redirect(flask.url_for('torrents.view', torrent_id=torrent.id))
|
||||
except backend.TorrentExtraValidationException:
|
||||
pass
|
||||
|
||||
# If we get here with a POST, it means the form data was invalid: return a non-okay status
|
||||
status_code = 400 if flask.request.method == 'POST' else 200
|
||||
return flask.render_template('upload.html', upload_form=upload_form), status_code
|
||||
|
||||
|
||||
@cached_function
|
||||
|
|
Loading…
Reference in a new issue