diff --git a/files/__main__.py b/files/__main__.py index a773e79b0..fe1137c5c 100644 --- a/files/__main__.py +++ b/files/__main__.py @@ -60,8 +60,9 @@ if "load_chat" in argv: def get_CF(): with app.app_context(): x = request.headers.get('CF-Connecting-IP') - if x: return x - return request.headers.get('X-Forwarded-For') + if not x: + x = request.headers.get('X-Forwarded-For') + return x limiter = Limiter( app=app, diff --git a/files/routes/admin.py b/files/routes/admin.py index 9308752d9..4afc7227e 100644 --- a/files/routes/admin.py +++ b/files/routes/admin.py @@ -25,6 +25,7 @@ from files.routes.routehelpers import get_alt_graph, get_alt_graph_ids from .front import frontlist, comment_idlist @app.get('/admin/loggedin') +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @admin_level_required(PERMS['VIEW_ACTIVE_USERS']) def loggedin_list(v): @@ -33,6 +34,7 @@ def loggedin_list(v): return render_template("admin/loggedin.html", v=v, users=users) @app.get('/admin/loggedout') +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @admin_level_required(PERMS['VIEW_ACTIVE_USERS']) def loggedout_list(v): @@ -40,6 +42,7 @@ def loggedout_list(v): return render_template("admin/loggedout.html", v=v, users=users) @app.get('/admin/dm_images') +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @admin_level_required(PERMS['VIEW_DM_IMAGES']) def dm_images(v): @@ -60,6 +63,7 @@ def dm_images(v): return render_template("admin/dm_images.html", v=v, items=items, next_exists=next_exists, page=page) @app.get('/admin/edit_rules') +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @admin_level_required(PERMS['EDIT_RULES']) def edit_rules_get(v): @@ -92,6 +96,7 @@ def edit_rules_post(v): @app.post("/@/make_admin") @limiter.limit('1/second', scope=path) +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @admin_level_required(PERMS['ADMIN_ADD']) def make_admin(v:User, username): @@ -114,6 +119,7 @@ def make_admin(v:User, username): @app.post("/@/remove_admin") @limiter.limit('1/second', scope=path) +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @admin_level_required(PERMS['ADMIN_REMOVE']) def remove_admin(v:User, username): @@ -142,6 +148,7 @@ def remove_admin(v:User, username): @app.post("/distribute/") @limiter.limit('1/second', scope=path) +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @admin_level_required(PERMS['POST_BETS_DISTRIBUTE']) def distribute(v:User, option_id): @@ -200,6 +207,7 @@ def distribute(v:User, option_id): @app.post("/@/revert_actions") @limiter.limit('1/second', scope=path) +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @admin_level_required(PERMS['ADMIN_ACTIONS_REVERT']) def revert_actions(v:User, username): @@ -253,6 +261,7 @@ def revert_actions(v:User, username): return {"message": f"@{revertee.username}'s admin actions have been reverted!"} @app.get("/admin/shadowbanned") +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @admin_level_required(PERMS['USER_SHADOWBAN']) def shadowbanned(v): @@ -266,6 +275,7 @@ def shadowbanned(v): @app.get("/admin/image_posts") +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @admin_level_required(PERMS['POST_COMMENT_MODERATION']) def image_posts_listing(v): @@ -285,6 +295,7 @@ def image_posts_listing(v): @app.get("/admin/reported/posts") +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @admin_level_required(PERMS['POST_COMMENT_MODERATION']) def reported_posts(v): @@ -309,6 +320,7 @@ def reported_posts(v): @app.get("/admin/reported/comments") +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @admin_level_required(PERMS['POST_COMMENT_MODERATION']) def reported_comments(v): @@ -337,6 +349,7 @@ def reported_comments(v): standalone=True) @app.get("/admin") +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @admin_level_required(PERMS['ADMIN_HOME_VISIBLE']) def admin_home(v): @@ -344,6 +357,7 @@ def admin_home(v): @app.post("/admin/site_settings/") @limiter.limit('1/second', scope=path) +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @admin_level_required(PERMS['SITE_SETTINGS']) def change_settings(v:User, setting): @@ -372,6 +386,7 @@ def change_settings(v:User, setting): @app.post("/admin/clear_cloudflare_cache") @limiter.limit('1/second', scope=path) +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @admin_level_required(PERMS['SITE_CACHE_PURGE_CDN']) def clear_cloudflare_cache(v): @@ -396,6 +411,7 @@ def admin_badges_grantable_list(v): @app.get("/admin/badge_grant") @app.get("/admin/badge_remove") @feature_required('BADGES') +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @admin_level_required(PERMS['USER_BADGES']) def badge_grant_get(v): @@ -406,8 +422,9 @@ def badge_grant_get(v): badge_types=badge_types, grant=grant) @app.post("/admin/badge_grant") -@limiter.limit('1/second', scope=path) @feature_required('BADGES') +@limiter.limit('1/second', scope=path) +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @admin_level_required(PERMS['USER_BADGES']) def badge_grant_post(v): @@ -467,8 +484,9 @@ def badge_grant_post(v): return render_template("admin/badge_admin.html", v=v, badge_types=badges, grant=True, msg=f"{new_badge.name} Badge granted to @{user.username} successfully!") @app.post("/admin/badge_remove") -@limiter.limit('1/second', scope=path) @feature_required('BADGES') +@limiter.limit('1/second', scope=path) +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @admin_level_required(PERMS['USER_BADGES']) def badge_remove_post(v): @@ -504,6 +522,7 @@ def badge_remove_post(v): @app.get("/admin/alt_votes") +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @admin_level_required(PERMS['VIEW_ALT_VOTES']) def alt_votes_get(v): @@ -610,6 +629,7 @@ def alt_votes_get(v): @app.get("/admin/alts/") @app.get("/@/alts/") +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @admin_level_required(PERMS['USER_LINK']) def admin_view_alts(v:User, username=None): @@ -618,6 +638,7 @@ def admin_view_alts(v:User, username=None): @app.post('/@/alts/') @limiter.limit('1/second', scope=path) +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @admin_level_required(PERMS['USER_LINK']) def admin_add_alt(v:User, username): @@ -653,6 +674,7 @@ def admin_add_alt(v:User, username): @app.post('/@/alts//deleted') @limiter.limit('1/second', scope=path) +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @admin_level_required(PERMS['USER_LINK']) def admin_delink_relink_alt(v:User, username, other): @@ -675,6 +697,7 @@ def admin_delink_relink_alt(v:User, username, other): @app.get("/admin/removed/posts") +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @admin_level_required(PERMS['POST_COMMENT_MODERATION']) def admin_removed(v): @@ -697,6 +720,7 @@ def admin_removed(v): @app.get("/admin/removed/comments") +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @admin_level_required(PERMS['POST_COMMENT_MODERATION']) def admin_removed_comments(v): @@ -717,6 +741,7 @@ def admin_removed_comments(v): @app.post("/unagendaposter/") @limiter.limit('1/second', scope=path) +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @admin_level_required(PERMS['USER_AGENDAPOSTER']) def unagendaposter(id, v): @@ -757,6 +782,7 @@ def unagendaposter(id, v): @app.post("/shadowban/") @limiter.limit('1/second', scope=path) +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @admin_level_required(PERMS['USER_SHADOWBAN']) def shadowban(user_id, v): @@ -792,6 +818,7 @@ def shadowban(user_id, v): @app.post("/unshadowban/") @limiter.limit('1/second', scope=path) +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @admin_level_required(PERMS['USER_SHADOWBAN']) def unshadowban(user_id, v): @@ -819,6 +846,7 @@ def unshadowban(user_id, v): @app.post("/admin/title_change/") @limiter.limit('1/second', scope=path) +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @admin_level_required(PERMS['USER_TITLE_CHANGE']) def admin_title_change(user_id, v): @@ -863,6 +891,7 @@ def admin_title_change(user_id, v): @app.post("/ban_user/") @limiter.limit('1/second', scope=path) +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @admin_level_required(PERMS['USER_BAN']) def ban_user(id, v): @@ -955,6 +984,7 @@ def ban_user(id, v): @app.post("/agendaposter/") @limiter.limit('1/second', scope=path) +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @admin_level_required(PERMS['USER_AGENDAPOSTER']) def agendaposter(id, v): @@ -1050,6 +1080,7 @@ def agendaposter(id, v): @app.post("/unban_user/") @limiter.limit('1/second', scope=path) +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @admin_level_required(PERMS['USER_BAN']) def unban_user(id, v): @@ -1095,6 +1126,7 @@ def unban_user(id, v): @app.post("/mute_user/") @limiter.limit('1/second', scope=path) +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @admin_level_required(PERMS['USER_BAN']) def mute_user(v:User, user_id): @@ -1116,6 +1148,7 @@ def mute_user(v:User, user_id): @app.post("/unmute_user/") @limiter.limit('1/second', scope=path) +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @admin_level_required(PERMS['USER_BAN']) def unmute_user(v:User, user_id): @@ -1135,6 +1168,7 @@ def unmute_user(v:User, user_id): @app.post("/admin/progstack/post/") @limiter.limit('1/second', scope=path) +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @admin_level_required(PERMS['PROGSTACK']) def progstack_post(post_id, v): @@ -1155,6 +1189,7 @@ def progstack_post(post_id, v): @app.post("/admin/unprogstack/post/") @limiter.limit('1/second', scope=path) +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @admin_level_required(PERMS['PROGSTACK']) def unprogstack_post(post_id, v): @@ -1173,6 +1208,7 @@ def unprogstack_post(post_id, v): @app.post("/admin/progstack/comment/") @limiter.limit('1/second', scope=path) +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @admin_level_required(PERMS['PROGSTACK']) def progstack_comment(comment_id, v): @@ -1193,6 +1229,7 @@ def progstack_comment(comment_id, v): @app.post("/admin/unprogstack/comment/") @limiter.limit('1/second', scope=path) +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @admin_level_required(PERMS['PROGSTACK']) def unprogstack_comment(comment_id, v): @@ -1211,6 +1248,7 @@ def unprogstack_comment(comment_id, v): @app.post("/remove_post/") @limiter.limit('1/second', scope=path) +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @admin_level_required(PERMS['POST_COMMENT_MODERATION']) def remove_post(post_id, v): @@ -1240,6 +1278,7 @@ def remove_post(post_id, v): @app.post("/approve_post/") @limiter.limit('1/second', scope=path) +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @admin_level_required(PERMS['POST_COMMENT_MODERATION']) def approve_post(post_id, v): @@ -1272,6 +1311,7 @@ def approve_post(post_id, v): @app.post("/distinguish/") @limiter.limit('1/second', scope=path) +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @admin_level_required(PERMS['POST_COMMENT_DISTINGUISH']) def distinguish_post(post_id, v): @@ -1299,8 +1339,9 @@ def distinguish_post(post_id, v): @app.post("/sticky/") -@limiter.limit('1/second', scope=path) @feature_required('PINS') +@limiter.limit('1/second', scope=path) +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @admin_level_required(PERMS['POST_COMMENT_MODERATION']) def sticky_post(post_id, v): @@ -1346,6 +1387,7 @@ def sticky_post(post_id, v): @app.post("/unsticky/") @limiter.limit('1/second', scope=path) +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @admin_level_required(PERMS['POST_COMMENT_MODERATION']) def unsticky_post(post_id, v): @@ -1376,6 +1418,7 @@ def unsticky_post(post_id, v): @app.post("/sticky_comment/") @limiter.limit('1/second', scope=path) +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @admin_level_required(PERMS['POST_COMMENT_MODERATION']) def sticky_comment(cid, v): @@ -1413,6 +1456,7 @@ def sticky_comment(cid, v): @app.post("/unsticky_comment/") @limiter.limit('1/second', scope=path) +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @admin_level_required(PERMS['POST_COMMENT_MODERATION']) def unsticky_comment(cid, v): @@ -1446,6 +1490,7 @@ def unsticky_comment(cid, v): @app.post("/remove_comment/") @limiter.limit('1/second', scope=path) +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @admin_level_required(PERMS['POST_COMMENT_MODERATION']) def remove_comment(c_id, v): @@ -1467,6 +1512,7 @@ def remove_comment(c_id, v): @app.post("/approve_comment/") @limiter.limit('1/second', scope=path) +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @admin_level_required(PERMS['POST_COMMENT_MODERATION']) def approve_comment(c_id, v): @@ -1494,6 +1540,7 @@ def approve_comment(c_id, v): @app.post("/distinguish_comment/") @limiter.limit('1/second', scope=path) +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @admin_level_required(PERMS['POST_COMMENT_DISTINGUISH']) def admin_distinguish_comment(c_id, v): @@ -1520,6 +1567,7 @@ def admin_distinguish_comment(c_id, v): else: return {"message": "Comment undistinguished!"} @app.get("/admin/banned_domains/") +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @admin_level_required(PERMS['DOMAINS_BAN']) def admin_banned_domains(v): @@ -1530,6 +1578,7 @@ def admin_banned_domains(v): @app.post("/admin/ban_domain") @limiter.limit('1/second', scope=path) +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @admin_level_required(PERMS['DOMAINS_BAN']) def ban_domain(v): @@ -1562,6 +1611,7 @@ def ban_domain(v): @app.post("/admin/unban_domain/") @limiter.limit('1/second', scope=path) +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @admin_level_required(PERMS['DOMAINS_BAN']) def unban_domain(v:User, domain): @@ -1582,6 +1632,7 @@ def unban_domain(v:User, domain): @app.post("/admin/nuke_user") @limiter.limit('1/second', scope=path) +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @admin_level_required(PERMS['POST_COMMENT_MODERATION']) def admin_nuke_user(v): @@ -1616,6 +1667,7 @@ def admin_nuke_user(v): @app.post("/admin/unnuke_user") @limiter.limit('1/second', scope=path) +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @admin_level_required(PERMS['POST_COMMENT_MODERATION']) def admin_nunuke_user(v): @@ -1651,6 +1703,7 @@ def admin_nunuke_user(v): @app.post("/blacklist/") @limiter.limit('1/second', scope=path) +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @admin_level_required(PERMS['USER_BLACKLIST']) def blacklist_user(user_id, v): @@ -1672,6 +1725,7 @@ def blacklist_user(user_id, v): @app.post("/unblacklist/") @limiter.limit('1/second', scope=path) +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @admin_level_required(PERMS['USER_BLACKLIST']) def unblacklist_user(user_id, v): @@ -1693,6 +1747,7 @@ def unblacklist_user(user_id, v): return {"message": f"@{user.username} has been unblacklisted from restricted holes!"} @app.get('/admin/delete_media') +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @admin_level_required(PERMS['DELETE_MEDIA']) def delete_media_get(v): @@ -1700,6 +1755,7 @@ def delete_media_get(v): @app.post("/admin/delete_media") @limiter.limit('1/second', scope=path) +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @admin_level_required(PERMS['DELETE_MEDIA']) def delete_media_post(v): diff --git a/files/routes/asset_submissions.py b/files/routes/asset_submissions.py index 0877b1f0e..17c289d9a 100644 --- a/files/routes/asset_submissions.py +++ b/files/routes/asset_submissions.py @@ -15,6 +15,7 @@ from files.__main__ import app, cache, limiter ASSET_TYPES = (Marsey, HatDef) @app.get("/submit/marseys") +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @auth_required def submit_marseys(v:User): @@ -34,6 +35,7 @@ def submit_marseys(v:User): @app.post("/submit/marseys") @limiter.limit('1/second', scope=path) +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @auth_required def submit_marsey(v:User): @@ -108,6 +110,7 @@ def verify_permissions_and_get_asset(cls, asset_type:str, v:User, name:str, make @app.post("/admin/approve/marsey/") @limiter.limit('1/second', scope=path) +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @admin_level_required(PERMS['MODERATE_PENDING_SUBMITTED_ASSETS']) def approve_marsey(v, name): @@ -207,12 +210,14 @@ def remove_asset(cls, type_name:str, v:User, name:str) -> dict[str, str]: @app.post("/remove/marsey/") @limiter.limit('1/second', scope=path) +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @auth_required def remove_marsey(v:User, name): return remove_asset(Marsey, "marsey", v, name) @app.get("/submit/hats") +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @auth_required def submit_hats(v:User): @@ -224,6 +229,7 @@ def submit_hats(v:User): @app.post("/submit/hats") @limiter.limit('1/second', scope=path) +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @auth_required def submit_hat(v:User): @@ -359,12 +365,14 @@ def approve_hat(v, name): @app.post("/remove/hat/") @limiter.limit('1/second', scope=path) +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @auth_required def remove_hat(v:User, name): return remove_asset(HatDef, 'hat', v, name) @app.get("/admin/update/marseys") +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @admin_level_required(PERMS['UPDATE_ASSETS']) def update_marseys(v): @@ -384,6 +392,7 @@ def update_marseys(v): @app.post("/admin/update/marseys") @limiter.limit('1/second', scope=path) +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @admin_level_required(PERMS['UPDATE_ASSETS']) def update_marsey(v): @@ -435,6 +444,7 @@ def update_marsey(v): return render_template("update_assets.html", v=v, msg=f"'{name}' updated successfully!", name=name, tags=tags, type="Marsey") @app.get("/admin/update/hats") +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @admin_level_required(PERMS['UPDATE_ASSETS']) def update_hats(v): @@ -443,6 +453,7 @@ def update_hats(v): @app.post("/admin/update/hats") @limiter.limit('1/second', scope=path) +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @admin_level_required(PERMS['UPDATE_ASSETS']) def update_hat(v): diff --git a/files/routes/awards.py b/files/routes/awards.py index f0aba333a..ad395adcf 100644 --- a/files/routes/awards.py +++ b/files/routes/awards.py @@ -22,6 +22,7 @@ from .front import frontlist @app.get("/shop/awards") @app.get("/settings/shop") +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @auth_required def shop(v:User): @@ -129,6 +130,7 @@ def buy(v:User, award): @app.post("/award//") @limiter.limit('1/second', scope=path) +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @is_not_permabanned def award_thing(v, thing_type, id): diff --git a/files/routes/chat.py b/files/routes/chat.py index e42face4b..8ff7b5b74 100644 --- a/files/routes/chat.py +++ b/files/routes/chat.py @@ -29,6 +29,7 @@ muted = cache.get(f'muted') or {} messages = cache.get(f'messages') or {} @app.get("/chat") +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @admin_level_required(PERMS['CHAT']) def chat(v): diff --git a/files/routes/comments.py b/files/routes/comments.py index 7709cdc65..a014ddf71 100644 --- a/files/routes/comments.py +++ b/files/routes/comments.py @@ -28,6 +28,7 @@ WORDLE_COLOR_MAPPINGS = {-1: "🟥", 0: "🟨", 1: "🟩"} @app.get("/post///") @app.get("/h//comment/") @app.get("/h//post///") +@limiter.limit(DEFAULT_RATELIMIT) @auth_desired_with_logingate def post_pid_comment_cid(cid, pid=None, anything=None, v=None, sub=None): @@ -452,6 +453,7 @@ def edit_comment(cid, v): @app.post("/delete/comment/") @limiter.limit('1/second', scope=path) +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @auth_required def delete_comment(cid, v): @@ -474,6 +476,7 @@ def delete_comment(cid, v): @app.post("/undelete/comment/") @limiter.limit('1/second', scope=path) +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @auth_required def undelete_comment(cid, v): @@ -493,8 +496,9 @@ def undelete_comment(cid, v): return {"message": "Comment undeleted!"} @app.post("/pin_comment/") -@limiter.limit('1/second', scope=path) @feature_required('PINS') +@limiter.limit('1/second', scope=path) +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @auth_required def pin_comment(cid, v): @@ -519,6 +523,7 @@ def pin_comment(cid, v): @app.post("/unpin_comment/") @limiter.limit('1/second', scope=path) +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @auth_required def unpin_comment(cid, v): @@ -542,6 +547,7 @@ def unpin_comment(cid, v): @app.post("/save_comment/") @limiter.limit('1/second', scope=path) +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @auth_required def save_comment(cid, v): @@ -559,6 +565,7 @@ def save_comment(cid, v): @app.post("/unsave_comment/") @limiter.limit('1/second', scope=path) +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @auth_required def unsave_comment(cid, v): @@ -595,6 +602,7 @@ def diff_words(answer, guess): @app.post("/wordle/") @limiter.limit('1/second', scope=path) +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @auth_required def handle_wordle_action(cid, v): @@ -626,8 +634,9 @@ def handle_wordle_action(cid, v): @app.post("/toggle_comment_nsfw/") -@limiter.limit('1/second', scope=path) @feature_required('NSFW_MARKING') +@limiter.limit('1/second', scope=path) +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @auth_required def toggle_comment_nsfw(cid, v): diff --git a/files/routes/errors.py b/files/routes/errors.py index 7820c5f08..bfff42015 100644 --- a/files/routes/errors.py +++ b/files/routes/errors.py @@ -3,9 +3,12 @@ from urllib.parse import quote, urlencode from flask import redirect, render_template, request, session, g -from files.helpers.config.const import ERROR_MARSEYS, ERROR_MSGS, ERROR_TITLES, WERKZEUG_ERROR_DESCRIPTIONS, is_site_url +from files.helpers.config.const import * from files.helpers.settings import get_setting -from files.__main__ import app + +from files.routes.wrappers import path + +from files.__main__ import app, limiter # If you're adding an error, go here: # https://github.com/pallets/werkzeug/blob/main/src/werkzeug/exceptions.py @@ -59,6 +62,8 @@ def error_500(e): @app.post("/allow_nsfw") +@limiter.limit('1/second', scope=path) +@limiter.limit(DEFAULT_RATELIMIT) def allow_nsfw(): session["over_18"] = int(time.time()) + 3600 redir = request.values.get("redir", "/") diff --git a/files/routes/feeds.py b/files/routes/feeds.py index ca8789061..57b4c8139 100644 --- a/files/routes/feeds.py +++ b/files/routes/feeds.py @@ -11,6 +11,7 @@ from files.__main__ import app @app.get('/rss') @app.get('/feed') @app.get('/rss//') +@limiter.limit(DEFAULT_RATELIMIT) def feeds_user(sort='hot', t='all'): try: page = max(int(request.values.get("page", 1)), 1) diff --git a/files/routes/front.py b/files/routes/front.py index e20f59270..e1f9e396c 100644 --- a/files/routes/front.py +++ b/files/routes/front.py @@ -160,6 +160,7 @@ def frontlist(v=None, sort="hot", page=1, t="all", ids_only=True, filter_words=' @app.get("/random_post") +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @auth_required def random_post(v:User): @@ -173,6 +174,7 @@ def random_post(v:User): @app.get("/random_user") +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @auth_required def random_user(v:User): @@ -212,6 +214,7 @@ def comment_idlist(v=None, page=1, sort="new", t="day", gt=0, lt=0, site=None): return [x[0] for x in comments] @app.get("/comments") +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @auth_required def all_comments(v:User): diff --git a/files/routes/giphy.py b/files/routes/giphy.py index 2e39c6a1c..c1c343409 100644 --- a/files/routes/giphy.py +++ b/files/routes/giphy.py @@ -7,6 +7,7 @@ from files.__main__ import app @app.get("/giphy") @app.get("/giphy") +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @auth_required def giphy(v=None, path=None): diff --git a/files/routes/groups.py b/files/routes/groups.py index 4ecf857c9..0f5f2ca78 100644 --- a/files/routes/groups.py +++ b/files/routes/groups.py @@ -8,6 +8,7 @@ from files.routes.wrappers import * from files.__main__ import app, limiter @app.get("/ping_groups") +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @auth_required def ping_groups(v:User): @@ -16,6 +17,7 @@ def ping_groups(v:User): @app.post("/create_group") @limiter.limit('1/second', scope=path) +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @is_not_permabanned def create_group(v): @@ -54,6 +56,7 @@ def create_group(v): @app.post("/!/apply") @limiter.limit('1/second', scope=path) +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @auth_required def join_group(v:User, group_name): @@ -69,6 +72,7 @@ def join_group(v:User, group_name): @app.post("/!/leave") @limiter.limit('1/second', scope=path) +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @auth_required def leave_group(v:User, group_name): @@ -92,6 +96,7 @@ def leave_group(v:User, group_name): @app.get("/!") +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @auth_required def memberships(v:User, group_name): @@ -112,6 +117,7 @@ def memberships(v:User, group_name): @app.post("/!//approve") @limiter.limit('1/second', scope=path) +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @auth_required def group_approve(v:User, group_name, user_id): @@ -134,6 +140,7 @@ def group_approve(v:User, group_name, user_id): @app.post("/!//reject") @limiter.limit('1/second', scope=path) +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @auth_required def group_reject(v:User, group_name, user_id): diff --git a/files/routes/hats.py b/files/routes/hats.py index e93f70729..22302f32e 100644 --- a/files/routes/hats.py +++ b/files/routes/hats.py @@ -8,6 +8,7 @@ from files.routes.wrappers import * from files.__main__ import app, limiter @app.get("/shop/hats") +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @auth_required def hats(v:User): @@ -82,6 +83,7 @@ def buy_hat(v:User, hat_id): @app.post("/equip_hat/") @limiter.limit('1/second', scope=path) +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @auth_required def equip_hat(v:User, hat_id): @@ -98,6 +100,7 @@ def equip_hat(v:User, hat_id): @app.post("/unequip_hat/") @limiter.limit('1/second', scope=path) +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @auth_required def unequip_hat(v:User, hat_id): @@ -113,6 +116,7 @@ def unequip_hat(v:User, hat_id): return {"message": f"'{hat.name}' unequipped!"} @app.get("/hat_owners/") +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @auth_required def hat_owners(v:User, hat_id): diff --git a/files/routes/login.py b/files/routes/login.py index fddab0f74..29b693ef8 100644 --- a/files/routes/login.py +++ b/files/routes/login.py @@ -21,6 +21,7 @@ from files.routes.wrappers import * NO_LOGIN_REDIRECT_URLS = ("/login", "/logout", "/signup", "/forgot", "/reset", "/reset_2fa", "/lost_2fa") @app.get("/login") +@limiter.limit(DEFAULT_RATELIMIT) @auth_desired def login_get(v:Optional[User]): redir = request.values.get("redirect", "").strip().rstrip('?').lower() @@ -39,6 +40,7 @@ def login_deduct_when(resp): @app.post("/login") @limiter.limit('1/second', scope=path) +@limiter.limit(DEFAULT_RATELIMIT) @auth_desired @limiter.limit("6/minute;10/day", deduct_when=login_deduct_when) def login_post(v:Optional[User]): @@ -128,6 +130,7 @@ def on_login(account, redir=None): @app.get("/me") @app.get("/@me") +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @auth_required def me(v:User): @@ -137,6 +140,7 @@ def me(v:User): @app.post("/logout") @limiter.limit('1/second', scope=path) +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @auth_required def logout(v): @@ -147,6 +151,7 @@ def logout(v): return {"message": "Logout successful!"} @app.get("/signup") +@limiter.limit(DEFAULT_RATELIMIT) @auth_desired def sign_up_get(v:Optional[User]): if not get_setting('signups'): @@ -362,12 +367,14 @@ def sign_up_post(v:Optional[User]): @app.get("/forgot") +@limiter.limit(DEFAULT_RATELIMIT) def get_forgot(): return render_template("login/forgot_password.html") @app.post("/forgot") @limiter.limit('1/second', scope=path) +@limiter.limit(DEFAULT_RATELIMIT) def post_forgot(): username = request.values.get("username") @@ -403,6 +410,7 @@ def post_forgot(): @app.get("/reset") +@limiter.limit(DEFAULT_RATELIMIT) def get_reset(): user_id = request.values.get("id") timestamp = 0 @@ -432,6 +440,7 @@ def get_reset(): @app.post("/reset") @limiter.limit('1/second', scope=path) +@limiter.limit(DEFAULT_RATELIMIT) @auth_desired def post_reset(v:Optional[User]): if v: return redirect('/') @@ -470,6 +479,7 @@ def post_reset(v:Optional[User]): message="Login normally to access your account.") @app.get("/lost_2fa") +@limiter.limit(DEFAULT_RATELIMIT) @auth_desired def lost_2fa(v:Optional[User]): if v and not v.mfa_secret: abort(400, "You don't have 2FA enabled") @@ -515,6 +525,7 @@ def lost_2fa_post(): message="If the username, password, and email match, we will send you an email. Check your spam folder if you can't find it."), 202 @app.get("/reset_2fa") +@limiter.limit(DEFAULT_RATELIMIT) def reset_2fa(): now=int(time.time()) t = request.values.get("t") diff --git a/files/routes/lottery.py b/files/routes/lottery.py index 807a2ec62..312ecc7f5 100644 --- a/files/routes/lottery.py +++ b/files/routes/lottery.py @@ -8,6 +8,7 @@ from files.__main__ import app, limiter @app.post("/lottery/end") @limiter.limit('1/second', scope=path) +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @admin_level_required(PERMS['LOTTERY_ADMIN']) def lottery_end(v): @@ -17,6 +18,7 @@ def lottery_end(v): @app.post("/lottery/start") @limiter.limit('1/second', scope=path) +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @admin_level_required(PERMS['LOTTERY_ADMIN']) def lottery_start(v): @@ -53,6 +55,7 @@ def lottery_active(v:User): return {"message": "", "stats": {"user": v.lottery_stats, "lottery": lottery, "participants": participants}} @app.get("/admin/lottery/participants") +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @admin_level_required(PERMS['LOTTERY_VIEW_PARTICIPANTS']) def lottery_admin(v): diff --git a/files/routes/mail.py b/files/routes/mail.py index acdcb4a7b..94c59f38f 100644 --- a/files/routes/mail.py +++ b/files/routes/mail.py @@ -11,6 +11,7 @@ from files.__main__ import app, limiter @app.post("/verify_email") @limiter.limit('1/second', scope=path) +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @auth_required def verify_email(v): @@ -19,6 +20,7 @@ def verify_email(v): @app.get("/activate") +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @auth_required def activate(v:User): diff --git a/files/routes/notifications.py b/files/routes/notifications.py index 0e18393a1..494f8db93 100644 --- a/files/routes/notifications.py +++ b/files/routes/notifications.py @@ -12,6 +12,7 @@ from files.__main__ import app @app.post("/clear") @limiter.limit('1/second', scope=path) +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @auth_required def clear(v): @@ -26,6 +27,7 @@ def clear(v): @app.get("/unread") +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @auth_required def unread(v): @@ -44,6 +46,7 @@ def unread(v): @app.get("/notifications/modmail") +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @admin_level_required(PERMS['VIEW_MODMAIL']) def notifications_modmail(v): @@ -70,6 +73,7 @@ def notifications_modmail(v): @app.get("/notifications/messages") +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @auth_required def notifications_messages(v:User): @@ -140,6 +144,7 @@ def notifications_messages(v:User): @app.get("/notifications/posts") +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @auth_required def notifications_posts(v:User): @@ -183,6 +188,7 @@ def notifications_posts(v:User): @app.get("/notifications/modactions") +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @auth_required def notifications_modactions(v:User): @@ -229,6 +235,7 @@ def notifications_modactions(v:User): @app.get("/notifications/reddit") +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @auth_required def notifications_reddit(v:User): @@ -267,6 +274,7 @@ def notifications_reddit(v:User): @app.get("/notifications") +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @auth_required def notifications(v:User): diff --git a/files/routes/oauth.py b/files/routes/oauth.py index c242193d8..7117d6dc4 100644 --- a/files/routes/oauth.py +++ b/files/routes/oauth.py @@ -8,6 +8,7 @@ from files.routes.wrappers import * from files.__main__ import app, limiter @app.get("/authorize") +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @auth_required def authorize_prompt(v:User): @@ -18,6 +19,7 @@ def authorize_prompt(v:User): @app.post("/authorize") @limiter.limit('1/second', scope=path) +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @auth_required def authorize(v): @@ -38,6 +40,7 @@ def authorize(v): @app.post("/rescind/") @limiter.limit('1/second', scope=path) +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @auth_required def rescind(v, aid): @@ -50,6 +53,7 @@ def rescind(v, aid): @app.post("/api_keys") @limiter.limit('1/second', scope=path) +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @is_not_permabanned def request_api_keys(v): @@ -91,6 +95,7 @@ def request_api_keys(v): @app.post("/delete_app/") @limiter.limit('1/second', scope=path) +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @auth_required def delete_oauth_app(v, aid): @@ -114,6 +119,7 @@ def delete_oauth_app(v, aid): @app.post("/edit_app/") @limiter.limit('1/second', scope=path) +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @is_not_permabanned def edit_oauth_app(v, aid): @@ -138,6 +144,7 @@ def edit_oauth_app(v, aid): @app.post("/admin/app/approve/") @limiter.limit('1/second', scope=path) +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @admin_level_required(PERMS['APPS_MODERATION']) def admin_app_approve(v, aid): @@ -175,6 +182,7 @@ def admin_app_approve(v, aid): @app.post("/admin/app/revoke/") @limiter.limit('1/second', scope=path) +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @admin_level_required(PERMS['APPS_MODERATION']) def admin_app_revoke(v, aid): @@ -201,6 +209,7 @@ def admin_app_revoke(v, aid): @app.post("/admin/app/reject/") @limiter.limit('1/second', scope=path) +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @admin_level_required(PERMS['APPS_MODERATION']) def admin_app_reject(v, aid): @@ -227,6 +236,7 @@ def admin_app_reject(v, aid): @app.get("/admin/app//posts") +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @admin_level_required(PERMS['APPS_MODERATION']) def admin_app_id_posts(v, aid): @@ -249,6 +259,7 @@ def admin_app_id_posts(v, aid): ) @app.get("/admin/app//comments") +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @admin_level_required(PERMS['APPS_MODERATION']) def admin_app_id_comments(v, aid): @@ -276,6 +287,7 @@ def admin_app_id_comments(v, aid): @app.get("/admin/apps") +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @admin_level_required(PERMS['APPS_MODERATION']) def admin_apps_list(v): @@ -287,6 +299,7 @@ def admin_apps_list(v): @app.post("/reroll/") @limiter.limit('1/second', scope=path) +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @auth_required def reroll_oauth_tokens(aid, v): diff --git a/files/routes/polls.py b/files/routes/polls.py index 50e6a938e..94b204163 100644 --- a/files/routes/polls.py +++ b/files/routes/polls.py @@ -7,6 +7,7 @@ from files.__main__ import app @app.post("/vote/post/option/") @limiter.limit('1/second', scope=path) +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @is_not_permabanned def vote_option(option_id, v): @@ -54,6 +55,7 @@ def vote_option(option_id, v): return {"message": "Bet successful!"} @app.get("/votes/post/option/") +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @auth_required def option_votes(option_id, v): @@ -87,6 +89,7 @@ def option_votes(option_id, v): @app.post("/vote/comment/option/") @limiter.limit('1/second', scope=path) +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @is_not_permabanned def vote_option_comment(option_id, v): @@ -122,6 +125,7 @@ def vote_option_comment(option_id, v): return "", 204 @app.get("/votes/comment/option/") +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @auth_required def option_votes_comment(option_id, v): diff --git a/files/routes/posts.py b/files/routes/posts.py index 899e5002e..ab9a3a0fb 100644 --- a/files/routes/posts.py +++ b/files/routes/posts.py @@ -34,6 +34,7 @@ titleheaders = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWe @app.post("/publish/") @limiter.limit('1/second', scope=path) +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @auth_required def publish(pid, v): @@ -66,6 +67,7 @@ def publish(pid, v): @app.get("/submit") @app.get("/h//submit") +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @auth_required def submit_get(v:User, sub=None): @@ -80,6 +82,7 @@ def submit_get(v:User, sub=None): @app.get("/post//") @app.get("/h//post/") @app.get("/h//post//") +@limiter.limit(DEFAULT_RATELIMIT) @auth_desired_with_logingate def post_id(pid, anything=None, v=None, sub=None): post = get_post(pid, v=v) @@ -174,6 +177,7 @@ def post_id(pid, anything=None, v=None, sub=None): fart=get_setting('fart_mode')) @app.get("/view_more///") +@limiter.limit(DEFAULT_RATELIMIT) @auth_desired_with_logingate def view_more(v, pid, sort, offset): post = get_post(pid, v=v) @@ -228,6 +232,7 @@ def view_more(v, pid, sort, offset): @app.get("/more_comments/") +@limiter.limit(DEFAULT_RATELIMIT) @auth_desired_with_logingate def more_comments(v, cid): try: cid = int(cid) @@ -474,6 +479,7 @@ def thumbnail_thread(pid:int, vid:int): @app.post("/is_repost") @limiter.limit('1/second', scope=path) +@limiter.limit(DEFAULT_RATELIMIT) def is_repost(): not_a_repost = {'permalink': ''} if not FEATURES['REPOST_DETECTION']: @@ -801,6 +807,7 @@ def submit_post(v:User, sub=None): @app.post("/delete_post/") @limiter.limit('1/second', scope=path) +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @auth_required def delete_post_pid(pid, v): @@ -828,6 +835,7 @@ def delete_post_pid(pid, v): @app.post("/undelete_post/") @limiter.limit('1/second', scope=path) +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @auth_required def undelete_post_pid(pid, v): @@ -849,8 +857,9 @@ def undelete_post_pid(pid, v): @app.post("/mark_post_nsfw/") -@limiter.limit('1/second', scope=path) @feature_required('NSFW_MARKING') +@limiter.limit('1/second', scope=path) +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @auth_required def mark_post_nsfw(pid, v): @@ -886,8 +895,9 @@ def mark_post_nsfw(pid, v): return {"message": "Post has been marked as +18!"} @app.post("/unmark_post_nsfw/") -@limiter.limit('1/second', scope=path) @feature_required('NSFW_MARKING') +@limiter.limit('1/second', scope=path) +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @auth_required def unmark_post_nsfw(pid, v): @@ -924,6 +934,7 @@ def unmark_post_nsfw(pid, v): @app.post("/save_post/") @limiter.limit('1/second', scope=path) +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @auth_required def save_post(pid, v): @@ -940,6 +951,7 @@ def save_post(pid, v): @app.post("/unsave_post/") @limiter.limit('1/second', scope=path) +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @auth_required def unsave_post(pid, v): @@ -955,6 +967,7 @@ def unsave_post(pid, v): @app.post("/pin/") @limiter.limit('1/second', scope=path) +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @auth_required def pin_post(post_id, v): @@ -969,6 +982,7 @@ def pin_post(post_id, v): return abort(404, "Post not found!") @app.put("/post//new") +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @auth_required def set_new_sort(post_id:int, v:User): @@ -990,6 +1004,7 @@ def set_new_sort(post_id:int, v:User): @app.delete("/post//new") +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @auth_required def unset_new_sort(post_id:int, v:User): diff --git a/files/routes/push_notifs.py b/files/routes/push_notifs.py index d9b5da329..eb3e6853c 100644 --- a/files/routes/push_notifs.py +++ b/files/routes/push_notifs.py @@ -5,6 +5,7 @@ from files.classes.push_subscriptions import PushSubscription @app.post("/push_subscribe") @limiter.limit('1/second', scope=path) +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @auth_required def push_subscribe(v): diff --git a/files/routes/reporting.py b/files/routes/reporting.py index efdcb0c37..f1fb0db8b 100644 --- a/files/routes/reporting.py +++ b/files/routes/reporting.py @@ -13,6 +13,7 @@ from files.__main__ import app, limiter, cache @app.post("/report/post/") @limiter.limit('1/second', scope=path) +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @auth_required def flag_post(pid, v): @@ -69,6 +70,7 @@ def flag_post(pid, v): @app.post("/report/comment/") @limiter.limit('1/second', scope=path) +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @auth_required def flag_comment(cid, v): diff --git a/files/routes/search.py b/files/routes/search.py index db7fecf14..43f09093a 100644 --- a/files/routes/search.py +++ b/files/routes/search.py @@ -44,6 +44,7 @@ def searchparse(text): return criteria @app.get("/search/posts") +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @auth_required def searchposts(v:User): @@ -175,6 +176,7 @@ def searchposts(v:User): ) @app.get("/search/comments") +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @auth_required def searchcomments(v:User): @@ -279,6 +281,7 @@ def searchcomments(v:User): @app.get("/search/messages") +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @auth_required def searchmessages(v:User): @@ -358,6 +361,7 @@ def searchmessages(v:User): return render_template("search_comments.html", v=v, query=query, total=total, page=page, comments=comments, sort=sort, t=t, next_exists=next_exists, standalone=True) @app.get("/search/users") +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @auth_required def searchusers(v:User): diff --git a/files/routes/settings.py b/files/routes/settings.py index 784c5b878..d9fa924c4 100644 --- a/files/routes/settings.py +++ b/files/routes/settings.py @@ -25,18 +25,21 @@ from files.__main__ import app, cache, limiter @app.get("/settings") +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @auth_required def settings(v:User): return redirect("/settings/personal") @app.get("/settings/personal") +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @auth_required def settings_personal(v:User): return render_template("settings/personal.html", v=v, error=get_error(), msg=get_msg()) @app.delete('/settings/background') +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @auth_required def remove_background(v): @@ -49,6 +52,7 @@ def remove_background(v): @app.post('/settings/custom_background') @limiter.limit('1/second', scope=path) +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @auth_required def upload_custom_background(v): @@ -73,6 +77,7 @@ def upload_custom_background(v): @app.post('/settings/profile_background') @limiter.limit('1/second', scope=path) +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @auth_required def upload_profile_background(v): @@ -93,6 +98,7 @@ def upload_profile_background(v): return redirect(f'/@{v.username}') @app.delete('/settings/profile_background') +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @auth_required def delete_profile_background(v): @@ -103,6 +109,7 @@ def delete_profile_background(v): @app.post("/settings/personal") @limiter.limit('1/second', scope=path) +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @auth_required def settings_personal_post(v): @@ -360,6 +367,7 @@ def settings_personal_post(v): @app.post("/settings/filters") @limiter.limit('1/second', scope=path) +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @auth_required def filters(v:User): @@ -388,6 +396,7 @@ def set_color(v:User, attr:str, color:Optional[str]): @app.post("/settings/namecolor") @limiter.limit('1/second', scope=path) +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @auth_required def namecolor(v): @@ -395,6 +404,7 @@ def namecolor(v): @app.post("/settings/themecolor") @limiter.limit('1/second', scope=path) +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @auth_required def themecolor(v): @@ -402,6 +412,7 @@ def themecolor(v): @app.post("/settings/titlecolor") @limiter.limit('1/second', scope=path) +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @auth_required def titlecolor(v): @@ -409,6 +420,7 @@ def titlecolor(v): @app.post("/settings/verifiedcolor") @limiter.limit('1/second', scope=path) +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @auth_required def verifiedcolor(v): @@ -417,6 +429,7 @@ def verifiedcolor(v): @app.post("/settings/security") @limiter.limit('1/second', scope=path) +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @auth_required def settings_security_post(v): @@ -491,6 +504,7 @@ def settings_security_post(v): @app.post("/settings/log_out_all_others") @limiter.limit('1/second', scope=path) +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @auth_required def settings_log_out_others(v): @@ -507,6 +521,7 @@ def settings_log_out_others(v): @app.post("/settings/images/profile") @limiter.limit('1/second', scope=path) +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @auth_required def settings_images_profile(v): @@ -544,8 +559,9 @@ def settings_images_profile(v): @app.post("/settings/images/banner") -@limiter.limit('1/second', scope=path) @feature_required('USERS_PROFILE_BANNER') +@limiter.limit('1/second', scope=path) +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @auth_required def settings_images_banner(v): @@ -566,6 +582,7 @@ def settings_images_banner(v): return redirect("/settings/personal?msg=Banner successfully updated!") @app.get("/settings/css") +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @auth_required def settings_css_get(v:User): @@ -573,6 +590,7 @@ def settings_css_get(v:User): @app.post("/settings/css") @limiter.limit('1/second', scope=path) +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @auth_required def settings_css(v): @@ -585,6 +603,7 @@ def settings_css(v): @app.post("/settings/profilecss") @limiter.limit('1/second', scope=path) +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @auth_required def settings_profilecss(v): @@ -597,6 +616,7 @@ def settings_profilecss(v): return redirect("/settings/css?msg=Profile CSS successfully updated!") @app.get("/settings/security") +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @auth_required def settings_security(v:User): @@ -638,6 +658,7 @@ def settings_block_user(v): @app.post("/settings/unblock") @limiter.limit('1/second', scope=path) +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @auth_required def settings_unblock_user(v): @@ -651,12 +672,14 @@ def settings_unblock_user(v): return {"message": f"@{user.username} unblocked successfully!"} @app.get("/settings/apps") +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @auth_required def settings_apps(v:User): return render_template("settings/apps.html", v=v) @app.get("/settings/advanced") +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @auth_required def settings_advanced_get(v:User): @@ -664,6 +687,7 @@ def settings_advanced_get(v:User): @app.post("/settings/name_change") @limiter.limit('1/second', scope=path) +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @is_not_permabanned def settings_name_change(v): @@ -701,8 +725,8 @@ def settings_name_change(v): return redirect("/settings/personal?msg=Name successfully changed!") @app.post("/settings/song_change_mp3") -@limiter.limit('1/second', scope=path) @feature_required('USERS_PROFILE_SONG') +@limiter.limit('1/second', scope=path) @limiter.limit("10/day") @limiter.limit("10/day", key_func=get_ID) @auth_required @@ -766,8 +790,8 @@ def _change_song_youtube(vid, id): @app.post("/settings/song_change") -@limiter.limit('1/second', scope=path) @feature_required('USERS_PROFILE_SONG') +@limiter.limit('1/second', scope=path) @limiter.limit("10/day") @limiter.limit("10/day", key_func=get_ID) @auth_required @@ -820,6 +844,7 @@ def settings_song_change(v): @app.post("/settings/title_change") @limiter.limit('1/second', scope=path) +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @auth_required def settings_title_change(v): @@ -847,8 +872,9 @@ def settings_title_change(v): @app.post("/settings/pronouns_change") -@limiter.limit('1/second', scope=path) @feature_required('PRONOUNS') +@limiter.limit('1/second', scope=path) +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @auth_required def settings_pronouns_change(v): @@ -875,6 +901,7 @@ def settings_pronouns_change(v): @app.post("/settings/checkmark_text") @limiter.limit('1/second', scope=path) +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @auth_required def settings_checkmark_text(v): @@ -889,6 +916,7 @@ def settings_checkmark_text(v): if IS_FISTMAS(): @app.post("/events/fistmas2022/darkmode") @limiter.limit('1/second', scope=path) + @limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @auth_required def event_darkmode(v): diff --git a/files/routes/special.py b/files/routes/special.py index 7ec8c1c56..5f22fe4b4 100644 --- a/files/routes/special.py +++ b/files/routes/special.py @@ -1,8 +1,10 @@ from flask import g, render_template from files.helpers.get import get_accounts_dict +from files.helpers.config.const import * -from files.routes.wrappers import auth_required -from files.__main__ import app, cache +from files.routes.wrappers import * + +from files.__main__ import app, cache, limiter _special_leaderboard_query = """ WITH bet_options AS ( @@ -80,6 +82,8 @@ def _special_leaderboard_get(): @app.get('/events/worldcup2022/leaderboard') @app.get('/special/worldcup2022/leaderboard') +@limiter.limit(DEFAULT_RATELIMIT) +@limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @auth_required def get_leaderboard(v): if SITE_NAME != 'rDrama': diff --git a/files/routes/static.py b/files/routes/static.py index 16ede5f02..27f926776 100644 --- a/files/routes/static.py +++ b/files/routes/static.py @@ -19,11 +19,13 @@ from files.__main__ import app, cache, limiter @app.get("/r/drama/comments//") @app.get("/r/Drama/comments/<int:id>/<title>") +@limiter.limit(DEFAULT_RATELIMIT) def rdrama(id, title): id = ''.join(f'{x}/' for x in id) return redirect(f'/archives/drama/comments/{id}{title}.html') @app.get("/r/<subreddit>") +@limiter.limit(DEFAULT_RATELIMIT) @auth_desired def subreddit(subreddit, v): reddit = v.reddit if v else "old.reddit.com" @@ -31,6 +33,7 @@ def subreddit(subreddit, v): @app.get("/reddit/<subreddit>/comments/<path:path>") @app.get("/r/<subreddit>/comments/<path:path>") +@limiter.limit(DEFAULT_RATELIMIT) @auth_desired def reddit_post(subreddit, v, path): post_id = path.rsplit("/", 1)[0].replace('/', '') @@ -39,6 +42,7 @@ def reddit_post(subreddit, v, path): @app.get("/marseys") +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @auth_required def marseys(v:User): @@ -58,6 +62,7 @@ def marseys(v:User): return render_template("marseys.html", v=v, marseys=marseys) @app.get("/emojis") +@limiter.limit(DEFAULT_RATELIMIT) def emoji_list(): return get_emojis(g.db) @@ -80,12 +85,14 @@ def get_emojis(db:scoped_session): return emojis @app.get('/sidebar') +@limiter.limit(DEFAULT_RATELIMIT) @auth_desired def sidebar(v:Optional[User]): return render_template('sidebar.html', v=v) @app.get("/stats") +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @auth_required def participation_stats(v:User): @@ -94,16 +101,19 @@ def participation_stats(v:User): return render_template("stats.html", v=v, title="Content Statistics", data=stats) @app.get("/chart") +@limiter.limit(DEFAULT_RATELIMIT) def chart(): return redirect('/weekly_chart') @app.get("/weekly_chart") +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @auth_required def weekly_chart(v:User): return send_file(statshelper.chart_path(kind="weekly", site=SITE)) @app.get("/daily_chart") +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @auth_required def daily_chart(v:User): @@ -111,6 +121,7 @@ def daily_chart(v:User): @app.get("/patrons") @app.get("/paypigs") +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @admin_level_required(PERMS['VIEW_PATRONS']) def patrons(v): @@ -120,6 +131,7 @@ def patrons(v): @app.get("/admins") @app.get("/badmins") +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @auth_required def admins(v:User): @@ -128,6 +140,7 @@ def admins(v:User): @app.get("/log") @app.get("/modlog") +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @auth_required def log(v:User): @@ -176,6 +189,7 @@ def log(v:User): return render_template("log.html", v=v, admins=admins, types=types, admin=admin, type=kind, actions=actions, next_exists=next_exists, page=page, single_user_url='admin') @app.get("/log/<int:id>") +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @auth_required def log_item(id, v): @@ -198,6 +212,7 @@ def log_item(id, v): return render_template("log.html", v=v, actions=[action], next_exists=False, page=1, action=action, admins=admins, types=types, single_user_url='admin') @app.get("/directory") +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @auth_required def static_megathread_index(v:User): @@ -211,6 +226,7 @@ def static_megathread_index(v:User): return render_template("megathread_index.html", v=v, emojis_hash=emojis_hash, emojis_count=emojis_count, emojis_size=emojis_size) @app.get("/api") +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @auth_required def api(v): @@ -222,6 +238,7 @@ def api(v): @app.get("/press") @app.get("/media") @app.get("/admin/chat") +@limiter.limit(DEFAULT_RATELIMIT) @auth_desired def contact(v:Optional[User]): return render_template("contact.html", v=v, msg=get_msg()) @@ -269,6 +286,7 @@ def submit_contact(v): return redirect("/contact?msg=Your message has been sent to the admins!") @app.get('/archives') +@limiter.limit(DEFAULT_RATELIMIT) def archivesindex(): return redirect("/archives/index.html") @@ -288,6 +306,7 @@ def badge_list(site): @app.get("/badges") @feature_required('BADGES') +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @auth_required def badges(v:User): @@ -295,6 +314,7 @@ def badges(v:User): return render_template("badges.html", v=v, badges=badges, counts=counts) @app.get("/blocks") +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @admin_level_required(PERMS['USER_BLOCKS_VISIBLE']) def blocks(v): @@ -311,23 +331,27 @@ def blocks(v): return render_template("blocks.html", v=v, users=users, targets=targets) @app.get("/formatting") +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @auth_required def formatting(v:User): return render_template("formatting.html", v=v) @app.get("/app") +@limiter.limit(DEFAULT_RATELIMIT) @auth_desired def mobile_app(v:Optional[User]): return render_template("app.html", v=v) @app.post("/dismiss_mobile_tip") @limiter.limit('1/second', scope=path) +@limiter.limit(DEFAULT_RATELIMIT) def dismiss_mobile_tip(): session["tooltip_last_dismissed"] = int(time.time()) return "", 204 @app.get("/transfers/<int:id>") +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @auth_required def transfers_id(id, v): @@ -342,6 +366,7 @@ def transfers_id(id, v): return render_template("transfers.html", v=v, page=1, comments=[transfer], standalone=True, next_exists=False) @app.get("/transfers") +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @auth_required def transfers(v:User): @@ -365,6 +390,7 @@ if not os.path.exists(f'files/templates/donate_{SITE_NAME}.html'): copyfile('files/templates/donate_rDrama.html', f'files/templates/donate_{SITE_NAME}.html') @app.get('/donate') +@limiter.limit(DEFAULT_RATELIMIT) @auth_desired_with_logingate def donate(v): return render_template(f'donate_{SITE_NAME}.html', v=v) diff --git a/files/routes/subs.py b/files/routes/subs.py index 13cc0f3c8..dc9e2c031 100644 --- a/files/routes/subs.py +++ b/files/routes/subs.py @@ -9,6 +9,7 @@ from files.__main__ import app, cache, limiter @app.post("/exile/post/<int:pid>") @limiter.limit('1/second', scope=path) +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @is_not_permabanned def exile_post(v:User, pid): @@ -42,6 +43,7 @@ def exile_post(v:User, pid): @app.post("/exile/comment/<int:cid>") @limiter.limit('1/second', scope=path) +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @is_not_permabanned def exile_comment(v:User, cid): @@ -75,6 +77,7 @@ def exile_comment(v:User, cid): @app.post("/h/<sub>/unexile/<int:uid>") @limiter.limit('1/second', scope=path) +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @is_not_permabanned def unexile(v:User, sub, uid): @@ -105,6 +108,7 @@ def unexile(v:User, sub, uid): @app.post("/h/<sub>/block") @limiter.limit('1/second', scope=path) +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @auth_required def block_sub(v:User, sub): @@ -118,6 +122,7 @@ def block_sub(v:User, sub): @app.post("/h/<sub>/unblock") @limiter.limit('1/second', scope=path) +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @auth_required def unblock_sub(v:User, sub): @@ -135,6 +140,7 @@ def unblock_sub(v:User, sub): @app.post("/h/<sub>/subscribe") @limiter.limit('1/second', scope=path) +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @auth_required def subscribe_sub(v:User, sub): @@ -148,6 +154,7 @@ def subscribe_sub(v:User, sub): @app.post("/h/<sub>/unsubscribe") @limiter.limit('1/second', scope=path) +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @auth_required def unsubscribe_sub(v:User, sub): @@ -160,6 +167,7 @@ def unsubscribe_sub(v:User, sub): @app.post("/h/<sub>/follow") @limiter.limit('1/second', scope=path) +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @auth_required def follow_sub(v:User, sub): @@ -176,6 +184,7 @@ def follow_sub(v:User, sub): @app.post("/h/<sub>/unfollow") @limiter.limit('1/second', scope=path) +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @auth_required def unfollow_sub(v:User, sub): @@ -188,6 +197,7 @@ def unfollow_sub(v:User, sub): return {"message": f"/h/{sub} unfollowed successfully!"} @app.get("/h/<sub>/mods") +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @auth_required def mods(v:User, sub): @@ -200,6 +210,7 @@ def mods(v:User, sub): @app.get("/h/<sub>/exilees") +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @auth_required def sub_exilees(v:User, sub): @@ -214,6 +225,7 @@ def sub_exilees(v:User, sub): @app.get("/h/<sub>/blockers") +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @auth_required def sub_blockers(v:User, sub): @@ -229,6 +241,7 @@ def sub_blockers(v:User, sub): @app.get("/h/<sub>/followers") +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @auth_required def sub_followers(v:User, sub): @@ -284,6 +297,7 @@ def add_mod(v:User, sub): @app.post("/h/<sub>/remove_mod") @limiter.limit('1/second', scope=path) +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @is_not_permabanned def remove_mod(v:User, sub): @@ -324,6 +338,7 @@ def remove_mod(v:User, sub): return {"message": f"@{user.username} has been removed as a mod!"} @app.get("/create_hole") +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @is_not_permabanned def create_sub(v): @@ -334,6 +349,7 @@ def create_sub(v): @app.post("/create_hole") @limiter.limit('1/second', scope=path) +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @is_not_permabanned def create_sub2(v): @@ -369,6 +385,7 @@ def create_sub2(v): @app.post("/kick/<int:pid>") @limiter.limit('1/second', scope=path) +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @is_not_permabanned def kick(v:User, pid): @@ -401,6 +418,7 @@ def kick(v:User, pid): return {"message": f"Post kicked from /h/{old} successfully!"} @app.get('/h/<sub>/settings') +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @is_not_permabanned def sub_settings(v:User, sub): @@ -411,6 +429,7 @@ def sub_settings(v:User, sub): @app.post('/h/<sub>/sidebar') @limiter.limit('1/second', scope=path) +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @is_not_permabanned def post_sub_sidebar(v:User, sub): @@ -436,6 +455,7 @@ def post_sub_sidebar(v:User, sub): @app.post('/h/<sub>/css') @limiter.limit('1/second', scope=path) +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @is_not_permabanned def post_sub_css(v:User, sub): @@ -467,6 +487,7 @@ def post_sub_css(v:User, sub): return redirect(f'/h/{sub}/settings') @app.get("/h/<sub>/css") +@limiter.limit(DEFAULT_RATELIMIT) def get_sub_css(sub): sub = g.db.query(Sub.css).filter_by(name=sub.strip().lower()).one_or_none() if not sub: abort(404) @@ -628,6 +649,7 @@ def sub_marsey(v:User, sub): @app.get("/flairs") @app.get("/holes") +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @auth_required def subs(v:User): @@ -637,6 +659,7 @@ def subs(v:User): @app.post("/hole_pin/<int:pid>") @limiter.limit('1/second', scope=path) +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @is_not_permabanned def hole_pin(v:User, pid): @@ -667,6 +690,7 @@ def hole_pin(v:User, pid): @app.post("/hole_unpin/<int:pid>") @limiter.limit('1/second', scope=path) +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @is_not_permabanned def hole_unpin(v:User, pid): @@ -698,6 +722,7 @@ def hole_unpin(v:User, pid): @app.post('/h/<sub>/stealth') @limiter.limit('1/second', scope=path) +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @is_not_permabanned def sub_stealth(v:User, sub): @@ -730,8 +755,9 @@ def sub_stealth(v:User, sub): @app.post("/mod_pin/<int:cid>") -@limiter.limit('1/second', scope=path) @feature_required('PINS') +@limiter.limit('1/second', scope=path) +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @is_not_permabanned def mod_pin(cid, v): @@ -761,6 +787,7 @@ def mod_pin(cid, v): @app.post("/unmod_pin/<int:cid>") @limiter.limit('1/second', scope=path) +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @is_not_permabanned def mod_unpin(cid, v): @@ -789,6 +816,7 @@ def mod_unpin(cid, v): @app.get("/h/<sub>/log") @app.get("/h/<sub>/modlog") +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @auth_required def hole_log(v:User, sub): @@ -831,6 +859,7 @@ def hole_log(v:User, sub): return render_template("log.html", v=v, admins=mods, types=types, admin=mod, type=kind, actions=actions, next_exists=next_exists, page=page, sub=sub, single_user_url='mod') @app.get("/h/<sub>/log/<int:id>") +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @auth_required def hole_log_item(id, v, sub): diff --git a/files/routes/users.py b/files/routes/users.py index 063e6408c..c5bb78895 100644 --- a/files/routes/users.py +++ b/files/routes/users.py @@ -55,6 +55,7 @@ def upvoters_downvoters(v, username, uid, cls, vote_cls, vote_dir, template, sta return render_template(template, next_exists=next_exists, listing=listing, page=page, v=v, standalone=standalone) @app.get("/@<username>/upvoters/<int:uid>/posts") +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @auth_required def upvoters_posts(v:User, username, uid): @@ -62,6 +63,7 @@ def upvoters_posts(v:User, username, uid): @app.get("/@<username>/upvoters/<int:uid>/comments") +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @auth_required def upvoters_comments(v:User, username, uid): @@ -69,6 +71,7 @@ def upvoters_comments(v:User, username, uid): @app.get("/@<username>/downvoters/<int:uid>/posts") +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @auth_required def downvoters_posts(v:User, username, uid): @@ -76,6 +79,7 @@ def downvoters_posts(v:User, username, uid): @app.get("/@<username>/downvoters/<int:uid>/comments") +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @auth_required def downvoters_comments(v:User, username, uid): @@ -110,6 +114,7 @@ def upvoting_downvoting(v, username, uid, cls, vote_cls, vote_dir, template, sta return render_template(template, next_exists=next_exists, listing=listing, page=page, v=v, standalone=standalone) @app.get("/@<username>/upvoting/<int:uid>/posts") +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @auth_required def upvoting_posts(v:User, username, uid): @@ -117,6 +122,7 @@ def upvoting_posts(v:User, username, uid): @app.get("/@<username>/upvoting/<int:uid>/comments") +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @auth_required def upvoting_comments(v:User, username, uid): @@ -124,6 +130,7 @@ def upvoting_comments(v:User, username, uid): @app.get("/@<username>/downvoting/<int:uid>/posts") +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @auth_required def downvoting_posts(v:User, username, uid): @@ -131,6 +138,7 @@ def downvoting_posts(v:User, username, uid): @app.get("/@<username>/downvoting/<int:uid>/comments") +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @auth_required def downvoting_comments(v:User, username, uid): @@ -165,6 +173,7 @@ def user_voted(v, username, cls, vote_cls, template, standalone): return render_template(template, next_exists=next_exists, listing=listing, page=page, v=v, standalone=standalone) @app.get("/@<username>/voted/posts") +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @auth_required def user_voted_posts(v:User, username): @@ -172,12 +181,14 @@ def user_voted_posts(v:User, username): @app.get("/@<username>/voted/comments") +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @auth_required def user_voted_comments(v:User, username): return user_voted(v, username, Comment, CommentVote, "userpage/voted_comments.html", True) @app.get("/banned") +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @auth_required def banned(v:User): @@ -191,6 +202,7 @@ def banned(v:User): return render_template("banned.html", v=v, users=users) @app.get("/grassed") +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @auth_required def grassed(v:User): @@ -204,6 +216,7 @@ def grassed(v:User): return render_template("grassed.html", v=v, users=users) @app.get("/chuds") +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @auth_required def chuds(v:User): @@ -219,7 +232,7 @@ def chuds(v:User): def all_upvoters_downvoters(v:User, username:str, vote_dir:int, is_who_simps_hates:bool): if username == 'Snappy': - abort(403, "For performance reasons, you can't see Snappy statistics!") + abort(403, "For performance reasons, you can't see Snappy's statistics!") vote_str = 'votes' simps_haters = 'voters' vote_name = 'Neutral' @@ -273,32 +286,36 @@ def all_upvoters_downvoters(v:User, username:str, vote_dir:int, is_who_simps_hat return render_template("userpage/voters.html", v=v, users=users, pos=pos, name=vote_name, name2=name2, total=total, page=page, next_exists=next_exists) @app.get("/@<username>/upvoters") +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @auth_required def upvoters(v:User, username:str): return all_upvoters_downvoters(v, username, 1, False) @app.get("/@<username>/downvoters") +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @auth_required def downvoters(v:User, username:str): return all_upvoters_downvoters(v, username, -1, False) @app.get("/@<username>/upvoting") +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @auth_required def upvoting(v:User, username:str): return all_upvoters_downvoters(v, username, 1, True) @app.get("/@<username>/downvoting") +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @auth_required def downvoting(v:User, username:str): return all_upvoters_downvoters(v, username, -1, True) @app.post("/@<username>/suicide") -@limiter.limit('1/second', scope=path) @feature_required('USERS_SUICIDE') +@limiter.limit('1/second', scope=path) @limiter.limit("5/day") @limiter.limit("5/day", key_func=get_ID) @auth_required @@ -311,6 +328,7 @@ def suicide(v:User, username:str): @app.get("/@<username>/coins") +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @auth_required def get_coins(v:User, username:str): @@ -359,20 +377,23 @@ def transfer_currency(v:User, username:str, currency_name:Literal['coins', 'mars @app.post("/@<username>/transfer_coins") @limiter.limit('1/second', scope=path) +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @is_not_permabanned def transfer_coins(v:User, username:str): return transfer_currency(v, username, 'coins', True) @app.post("/@<username>/transfer_bux") -@limiter.limit('1/second', scope=path) @feature_required('MARSEYBUX') +@limiter.limit('1/second', scope=path) +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @is_not_permabanned def transfer_bux(v:User, username:str): return transfer_currency(v, username, 'marseybux', False) @app.get("/leaderboard") +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @auth_required def leaderboard(v:User): @@ -403,6 +424,7 @@ def leaderboard(v:User): return render_template("leaderboard.html", v=v, leaderboards=leaderboards) @app.get("/<int:id>/css") +@limiter.limit(DEFAULT_RATELIMIT) def get_css(id): try: id = int(id) except: abort(404) @@ -426,6 +448,7 @@ def get_css(id): return resp @app.get("/<int:id>/profilecss") +@limiter.limit(DEFAULT_RATELIMIT) def get_profilecss(id): try: id = int(id) except: abort(404) @@ -447,6 +470,7 @@ def get_profilecss(id): return resp @app.get("/@<username>/song") +@limiter.limit(DEFAULT_RATELIMIT) def usersong(username:str): user = get_user(username) if user.song: return redirect(f"/songs/{user.song}.mp3") @@ -454,6 +478,7 @@ def usersong(username:str): @app.post("/subscribe/<int:post_id>") @limiter.limit('1/second', scope=path) +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @auth_required def subscribe(v, post_id): @@ -465,6 +490,7 @@ def subscribe(v, post_id): @app.post("/unsubscribe/<int:post_id>") @limiter.limit('1/second', scope=path) +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @auth_required def unsubscribe(v, post_id): @@ -627,6 +653,7 @@ def messagereply(v:User): return {"comment": render_template("comments.html", v=v, comments=[c])} @app.get("/2faqr/<secret>") +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @auth_required def mfa_qr(v:User, secret:str): @@ -670,17 +697,20 @@ def is_available(name:str): return {name: True} @app.get("/id/<int:id>") +@limiter.limit(DEFAULT_RATELIMIT) def user_id(id): user = get_account(id) return redirect(user.url) @app.get("/u/<username>") +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @auth_required def redditor_moment_redirect(v:User, username:str): return redirect(f"/@{username}") @app.get("/@<username>/followers") +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @auth_required def followers(v:User, username:str): @@ -703,6 +733,7 @@ def followers(v:User, username:str): return render_template("userpage/followers.html", v=v, u=u, users=users, page=page, next_exists=next_exists) @app.get("/@<username>/blockers") +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @auth_required def blockers(v:User, username:str): @@ -722,6 +753,7 @@ def blockers(v:User, username:str): return render_template("userpage/blockers.html", v=v, u=u, users=users, page=page, next_exists=next_exists) @app.get("/@<username>/following") +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @auth_required def following(v:User, username:str): @@ -743,6 +775,7 @@ def following(v:User, username:str): return render_template("userpage/following.html", v=v, u=u, users=users, page=page, next_exists=next_exists) @app.get("/@<username>/views") +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @auth_required def visitors(v:User, username:str): @@ -771,6 +804,7 @@ def userpagelisting(user:User, site=None, v=None, page:int=1, sort="new", t="all @app.get("/@<username>") @app.get("/@<username>.json") +@limiter.limit(DEFAULT_RATELIMIT) @auth_desired_with_logingate def u_username_wall(v:Optional[User], username:str): u = get_user(username, v=v, include_blocks=True, include_shadowbanned=False) @@ -824,6 +858,7 @@ def u_username_wall(v:Optional[User], username:str): @app.get("/@<username>/wall/comment/<int:cid>") @app.get("/@<username>/wall/comment/<int:cid>.json") +@limiter.limit(DEFAULT_RATELIMIT) @auth_desired_with_logingate def u_username_wall_comment(v:User, username:str, cid): comment = get_comment(cid, v=v) @@ -875,6 +910,7 @@ def u_username_wall_comment(v:User, username:str, cid): @app.get("/@<username>/posts") @app.get("/@<username>/posts.json") +@limiter.limit(DEFAULT_RATELIMIT) @auth_desired_with_logingate def u_username(v:Optional[User], username:str): u = get_user(username, v=v, include_blocks=True, include_shadowbanned=False) @@ -952,6 +988,7 @@ def u_username(v:Optional[User], username:str): @app.get("/@<username>/comments") @app.get("/@<username>/comments.json") +@limiter.limit(DEFAULT_RATELIMIT) @auth_desired_with_logingate def u_username_comments(username, v=None): u = get_user(username, v=v, include_blocks=True, include_shadowbanned=False) @@ -1020,6 +1057,7 @@ def u_username_comments(username, v=None): @app.get("/@<username>/info") +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @auth_required def u_username_info(username, v=None): @@ -1034,6 +1072,7 @@ def u_username_info(username, v=None): return user.json @app.get("/<int:id>/info") +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @auth_required def u_user_id_info(id, v=None): @@ -1049,6 +1088,7 @@ def u_user_id_info(id, v=None): @app.post("/follow/<username>") @limiter.limit('1/second', scope=path) +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @auth_required def follow_user(username, v): @@ -1076,6 +1116,7 @@ def follow_user(username, v): @app.post("/unfollow/<username>") @limiter.limit('1/second', scope=path) +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @auth_required def unfollow_user(username, v): @@ -1104,6 +1145,7 @@ def unfollow_user(username, v): @app.post("/remove_follow/<username>") @limiter.limit('1/second', scope=path) +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @auth_required def remove_follow(username, v): @@ -1168,6 +1210,7 @@ def get_saves_and_subscribes(v, template, relationship_cls, page:int, standalone return render_template(template, u=v, v=v, listing=listing, page=page, next_exists=next_exists, standalone=standalone) @app.get("/@<username>/saved/posts") +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @auth_required def saved_posts(v:User, username): @@ -1177,6 +1220,7 @@ def saved_posts(v:User, username): return get_saves_and_subscribes(v, "userpage/submissions.html", SaveRelationship, page, False) @app.get("/@<username>/saved/comments") +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @auth_required def saved_comments(v:User, username): @@ -1186,6 +1230,7 @@ def saved_comments(v:User, username): return get_saves_and_subscribes(v, "userpage/comments.html", CommentSaveRelationship, page, True) @app.get("/@<username>/subscribed/posts") +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @auth_required def subscribed_posts(v:User, username): @@ -1196,6 +1241,7 @@ def subscribed_posts(v:User, username): @app.post("/fp/<fp>") @limiter.limit('1/second', scope=path) +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @auth_required def fp(v:User, fp): @@ -1219,6 +1265,7 @@ def fp(v:User, fp): return '', 204 @app.get("/toggle_pins/<sort>") +@limiter.limit(DEFAULT_RATELIMIT) def toggle_pins(sort): if sort == 'hot': default = True else: default = False @@ -1232,6 +1279,7 @@ def toggle_pins(sort): @app.get("/toggle_holes") +@limiter.limit(DEFAULT_RATELIMIT) def toggle_holes(): if SITE_NAME == 'WPD': abort(404) @@ -1245,6 +1293,7 @@ def toggle_holes(): @app.get("/badge_owners/<int:bid>") +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @auth_required def bid_list(v:User, bid): @@ -1322,6 +1371,7 @@ def claim_rewards_all_users(): KOFI_TOKEN = environ.get("KOFI_TOKEN", "").strip() if KOFI_TOKEN: @app.post("/kofi") + @limiter.limit(DEFAULT_RATELIMIT) def kofi(): data = json.loads(request.values['data']) verification_token = data['verification_token'] @@ -1353,6 +1403,7 @@ if KOFI_TOKEN: @app.post("/gumroad") @limiter.limit('1/second', scope=path) +@limiter.limit(DEFAULT_RATELIMIT) def gumroad(): data = request.values ip = request.headers.get('CF-Connecting-IP') @@ -1385,6 +1436,7 @@ def gumroad(): @app.post("/settings/claim_rewards") @limiter.limit('1/second', scope=path) +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @auth_required def settings_claim_rewards(v:User): @@ -1401,6 +1453,7 @@ def settings_claim_rewards(v:User): return {"message": f"{patron} rewards claimed!"} @app.get("/users") +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @auth_required def users_list(v): diff --git a/files/routes/votes.py b/files/routes/votes.py index 1e23cdd4b..77fa3155d 100644 --- a/files/routes/votes.py +++ b/files/routes/votes.py @@ -8,6 +8,7 @@ from files.routes.routehelpers import get_alt_graph from math import floor @app.get("/votes/<link>") +@limiter.limit(DEFAULT_RATELIMIT) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @auth_required def vote_info_get(v, link): @@ -198,7 +199,6 @@ def vote_post_comment(target_id, new, v, cls, vote_cls): @limiter.limit("60/minute;1000/hour;2000/day") @limiter.limit("60/minute;1000/hour;2000/day", key_func=get_ID) @is_not_permabanned -@limiter.limit("1/second", key_func=lambda:f'{g.v.id}-{request.full_path}') def vote_post(post_id, new, v): return vote_post_comment(post_id, new, v, Submission, Vote) @@ -207,6 +207,5 @@ def vote_post(post_id, new, v): @limiter.limit("60/minute;1000/hour;2000/day") @limiter.limit("60/minute;1000/hour;2000/day", key_func=get_ID) @is_not_permabanned -@limiter.limit("1/second", key_func=lambda:f'{g.v.id}-{request.full_path}') def vote_comment(comment_id, new, v): return vote_post_comment(comment_id, new, v, Comment, CommentVote)