1
0
Fork 0
mirror of https://github.com/YunoHost/apps.git synced 2024-09-03 20:06:07 +02:00

store/wishlist_add: ratelimit wishlist proposal to once every 15 days per user

This commit is contained in:
Alexandre Aubin 2024-01-04 01:57:18 +01:00
parent e9524f63e6
commit 3db73ec95d
3 changed files with 42 additions and 11 deletions

View file

@ -31,6 +31,8 @@ from utils import (
get_wishlist,
get_stars,
get_app_md_and_screenshots,
save_wishlist_submit_for_ratelimit,
check_wishlist_submit_ratelimit,
)
app = Flask(__name__, static_url_path="/assets", static_folder="assets")
@ -199,7 +201,6 @@ def add_to_wishlist():
successmsg=None,
errormsg=errormsg,
)
csrf_token = request.form["csrf_token"]
if csrf_token != session.get("csrf_token"):
@ -222,6 +223,10 @@ def add_to_wishlist():
boring_keywords_to_check_for_people_not_reading_the_instructions = ["free", "open source", "open-source", "self-hosted", "simple", "lightweight", "light-weight", "best", "most", "fast", "flexible", "puissante", "powerful", "secure"]
checks = [
(
check_wishlist_submit_ratelimit(session['user']['username']) is True,
_("Proposing wishlist additions is limited to once every 15 days per user.")
),
(len(name) >= 3, _("App name should be at least 3 characters")),
(len(name) <= 30, _("App name should be less than 30 characters")),
(
@ -258,7 +263,7 @@ def add_to_wishlist():
_("Please focus on what the app does, without using marketing, fuzzy terms, or repeating that the app is 'free' and 'self-hostable'.")
),
(
description.lower().split()[0] != name an description.lower().split()[1] not in ["is", "est"],
description.lower().split()[0] != name and (len(description.split()) == 1 or description.lower().split()[1] not in ["is", "est"]),
_("No need to repeat '{app} is'. Focus on what the app does.")
)
]
@ -369,6 +374,9 @@ Description: {description}
"Your proposed app has succesfully been submitted. It must now be validated by the YunoHost team. You can track progress here: <a href='%(url)s'>%(url)s</a>",
url=url,
)
save_wishlist_submit_for_ratelimit(session['user']['username'])
return render_template(
"wishlist_add.html",
locale=get_locale(),

View file

@ -28,20 +28,22 @@
<i class="fa fa-exclamation-triangle fa-fw" aria-hidden="true"></i>
{{ _("You must first login to be allowed to submit an app to the wishlist") }}
<br/><br/>
</p>
<p class="mt-2 text-sm text-orange-700">
{{ _("Note that, due to various abuses, we restricted login on the app store to 'trust level 1' users.<br/><br/>'Trust level 1' is obtained after interacting a minimum with the forum, and more specifically: entering at least 5 topics, reading at least 30 posts, and spending at least 10 minutes reading posts.") }}
</p>
</div>
{% endif %}
<div role="alert" class="rounded-md border-s-4 border-sky-500 bg-sky-50 p-4">
<p class="mt-2 text-sm text-sky-700 font-bold">
<i class="fa fa-info-circle fa-fw" aria-hidden="true"></i>
{{ _("Please check the license of the app your are proposing") }}
{% else %}
<div role="alert" class="rounded-md border-s-4 border-orange-500 bg-orange-50 p-4 mb-5">
<p class="mt-2 text-sm text-orange-700 font-bold">
<i class="fa fa-exclamation-triangle fa-fw" aria-hidden="true"></i>
{{ _("Due to abuses, only one proposal every 15 days per user is allowed.") }}
</p>
<p class="mt-2 text-sm text-sky-700">
{{ _("The YunoHost project will only package free/open-source software (with possible case-by-case exceptions for apps which are not-totally-free)") }}
<p class="mt-2 text-sm text-orange-700">
{{ _("Reviewing those proposals is tiring for volunteers, please don't yolo-send every random nerdy stuff you find on the Internet.") }}
</p>
</div>
{% endif %}
{% if errormsg %}
<div role="alert" class="rounded-md border-s-4 border-red-500 bg-red-50 p-4 my-5">

View file

@ -1,3 +1,4 @@
import time
import base64
import os
import json
@ -6,7 +7,7 @@ import subprocess
import pycmarkgfm
from emoji import emojize
from flask import request
from hashlib import md5
AVAILABLE_LANGUAGES = ["en"] + os.listdir("translations")
@ -92,6 +93,26 @@ def get_stars():
get_stars.cache_checksum = None
get_stars()
def check_wishlist_submit_ratelimit(user):
dir_ = os.path.join(".wishlist_ratelimit")
if not os.path.exists(dir_):
os.mkdir(dir_)
f = os.path.join(dir_, md5(user.encode()).hexdigest())
return not os.path.exists(f) or (time.time() - os.path.getmtime(f)) > (15 * 24 * 3600) # 15 days
def save_wishlist_submit_for_ratelimit(user):
dir_ = os.path.join(".wishlist_ratelimit")
if not os.path.exists(dir_):
os.mkdir(dir_)
f = os.path.join(dir_, md5(user.encode()).hexdigest())
open(f, "w").write("")
def human_to_binary(size: str) -> int:
symbols = ("K", "M", "G", "T", "P", "E", "Z", "Y")