diff --git a/discordbot/titanembeds/database/guilds.py b/discordbot/titanembeds/database/guilds.py index ae819ca..164382e 100644 --- a/discordbot/titanembeds/database/guilds.py +++ b/discordbot/titanembeds/database/guilds.py @@ -11,6 +11,7 @@ class Guilds(Base): guest_icon = db.Column(db.String(255), default=None) # Guest icon url, None if unset chat_links = db.Column(db.Boolean()) # If users can post links bracket_links = db.Column(db.Boolean()) # If appending brackets to links to prevent embed + unauth_captcha = db.Column(db.Boolean(), nullable=False, server_default="1") # Enforce captcha on guest users mentions_limit = db.Column(db.Integer) # If there is a limit on the number of mentions in a msg roles = db.Column(db.Text().with_variant(db.Text(length=4294967295), 'mysql')) # Guild Roles channels = db.Column(db.Text().with_variant(db.Text(length=4294967295), 'mysql'))# Guild channels @@ -29,6 +30,7 @@ class Guilds(Base): self.guest_icon = None self.chat_links = True self.bracket_links = True + self.unauth_captcha = True self.mentions_limit = -1 # -1 = unlimited mentions self.roles = roles self.channels = channels diff --git a/webapp/alembic/versions/a5780c871aec_add_unauth_captcha_column_to_guilds.py b/webapp/alembic/versions/a5780c871aec_add_unauth_captcha_column_to_guilds.py new file mode 100644 index 0000000..03e02f6 --- /dev/null +++ b/webapp/alembic/versions/a5780c871aec_add_unauth_captcha_column_to_guilds.py @@ -0,0 +1,28 @@ +"""Add unauth_captcha column to guilds + +Revision ID: a5780c871aec +Revises: 109a6025e9ec +Create Date: 2017-11-04 01:07:47.658780 + +""" + +# revision identifiers, used by Alembic. +revision = 'a5780c871aec' +down_revision = '109a6025e9ec' +branch_labels = None +depends_on = None + +from alembic import op +import sqlalchemy as sa + + +def upgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.add_column('guilds', sa.Column('unauth_captcha', sa.Boolean(), server_default='1', nullable=False)) + # ### end Alembic commands ### + + +def downgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.drop_column('guilds', 'unauth_captcha') + # ### end Alembic commands ### diff --git a/webapp/titanembeds/blueprints/admin/admin.py b/webapp/titanembeds/blueprints/admin/admin.py index 326c403..73ff1ee 100644 --- a/webapp/titanembeds/blueprints/admin/admin.py +++ b/webapp/titanembeds/blueprints/admin/admin.py @@ -155,6 +155,7 @@ def administrate_guild(guild_id): "chat_links": db_guild.chat_links, "bracket_links": db_guild.bracket_links, "mentions_limit": db_guild.mentions_limit, + "unauth_captcha": db_guild.unauth_captcha, "icon": db_guild.icon, "discordio": db_guild.discordio if db_guild.discordio != None else "", "guest_icon": db_guild.guest_icon if db_guild.guest_icon != None else "", @@ -171,6 +172,7 @@ def update_administrate_guild(guild_id): db_guild.chat_links = request.form.get("chat_links", db_guild.chat_links) in ["true", True] db_guild.bracket_links = request.form.get("bracket_links", db_guild.bracket_links) in ["true", True] db_guild.mentions_limit = request.form.get("mentions_limit", db_guild.mentions_limit) + db_guild.unauth_captcha = request.form.get("unauth_captcha", db_guild.unauth_captcha) in ["true", True] discordio = request.form.get("discordio", db_guild.discordio) if discordio != None and discordio.strip() == "": discordio = None @@ -192,6 +194,7 @@ def update_administrate_guild(guild_id): mentions_limit=db_guild.mentions_limit, discordio=db_guild.discordio, guest_icon=db_guild.guest_icon, + unauth_captcha=unauth_captcha, ) @admin.route("/guilds") diff --git a/webapp/titanembeds/blueprints/api/api.py b/webapp/titanembeds/blueprints/api/api.py index 089088e..ab577d8 100644 --- a/webapp/titanembeds/blueprints/api/api.py +++ b/webapp/titanembeds/blueprints/api/api.py @@ -1,6 +1,6 @@ from titanembeds.database import db, Guilds, UnauthenticatedUsers, UnauthenticatedBans, AuthenticatedUsers, KeyValueProperties, GuildMembers, Messages, get_channel_messages, list_all_guild_members, get_guild_member, get_administrators_list from titanembeds.decorators import valid_session_required, discord_users_only -from titanembeds.utils import check_guild_existance, guild_accepts_visitors, guild_query_unauth_users_bool, get_client_ipaddr, discord_api, rate_limiter, channel_ratelimit_key, guild_ratelimit_key, user_unauthenticated, checkUserRevoke, checkUserBanned, update_user_status, check_user_in_guild, get_guild_channels, guild_webhooks_enabled +from titanembeds.utils import check_guild_existance, guild_accepts_visitors, guild_query_unauth_users_bool, get_client_ipaddr, discord_api, rate_limiter, channel_ratelimit_key, guild_ratelimit_key, user_unauthenticated, checkUserRevoke, checkUserBanned, update_user_status, check_user_in_guild, get_guild_channels, guild_webhooks_enabled, guild_unauthcaptcha_enabled from titanembeds.oauth import user_has_permission, generate_avatar_url, check_user_can_administrate_guild from flask import Blueprint, abort, jsonify, session, request, url_for from flask import current_app as app @@ -291,9 +291,6 @@ def create_unauthenticated_user(): guild_id = request.form['guild_id'] ip_address = get_client_ipaddr() username = username.strip() - captcha_response = request.form['captcha_response'] - if not verify_captcha_request(captcha_response, request.remote_addr): - abort(412) if len(username) < 2 or len(username) > 32: abort(406) if not all(x.isalnum() or x.isspace() or "-" == x or "_" == x for x in username): @@ -302,6 +299,10 @@ def create_unauthenticated_user(): abort(404) if not guild_query_unauth_users_bool(guild_id): abort(401) + if guild_unauthcaptcha_enabled(guild_id): + captcha_response = request.form['captcha_response'] + if not verify_captcha_request(captcha_response, request.remote_addr): + abort(412) if not checkUserBanned(guild_id, ip_address): session['username'] = username if 'user_id' not in session or len(str(session["user_id"])) > 4: diff --git a/webapp/titanembeds/blueprints/embed/embed.py b/webapp/titanembeds/blueprints/embed/embed.py index 943dd58..ed86b83 100644 --- a/webapp/titanembeds/blueprints/embed/embed.py +++ b/webapp/titanembeds/blueprints/embed/embed.py @@ -1,5 +1,5 @@ from flask import Blueprint, render_template, abort, redirect, url_for, session, request -from titanembeds.utils import check_guild_existance, guild_query_unauth_users_bool, guild_accepts_visitors +from titanembeds.utils import check_guild_existance, guild_query_unauth_users_bool, guild_accepts_visitors, guild_unauthcaptcha_enabled from titanembeds.oauth import generate_guild_icon_url, generate_avatar_url from titanembeds.database import db, Guilds, UserCSS from config import config @@ -70,6 +70,7 @@ def guild_embed(guild_id): generate_guild_icon=generate_guild_icon_url, unauth_enabled=guild_query_unauth_users_bool(guild_id), visitors_enabled=guild_accepts_visitors(guild_id), + unauth_captcha_enabled=guild_unauthcaptcha_enabled(guild_id), client_id=config['client-id'], recaptcha_site_key=config["recaptcha-site-key"], css=customcss, diff --git a/webapp/titanembeds/blueprints/user/user.py b/webapp/titanembeds/blueprints/user/user.py index 2fcd15b..c134ed3 100644 --- a/webapp/titanembeds/blueprints/user/user.py +++ b/webapp/titanembeds/blueprints/user/user.py @@ -209,6 +209,7 @@ def administrate_guild(guild_id): "chat_links": db_guild.chat_links, "bracket_links": db_guild.bracket_links, "mentions_limit": db_guild.mentions_limit, + "unauth_captcha": db_guild.unauth_captcha, "icon": db_guild.icon, "discordio": db_guild.discordio if db_guild.discordio != None else "", "guest_icon": db_guild.guest_icon if db_guild.guest_icon != None else "", @@ -231,6 +232,7 @@ def update_administrate_guild(guild_id): db_guild.chat_links = request.form.get("chat_links", db_guild.chat_links) in ["true", True] db_guild.bracket_links = request.form.get("bracket_links", db_guild.bracket_links) in ["true", True] db_guild.mentions_limit = request.form.get("mentions_limit", db_guild.mentions_limit) + db_guild.unauth_captcha = request.form.get("unauth_captcha", db_guild.unauth_captcha) in ["true", True] discordio = request.form.get("discordio", db_guild.discordio) if discordio != None and discordio.strip() == "": @@ -255,6 +257,7 @@ def update_administrate_guild(guild_id): mentions_limit=db_guild.mentions_limit, discordio=db_guild.discordio, guest_icon=guest_icon, + unauth_captcha=db_guild.unauth_captcha, ) @user.route("/add-bot/") diff --git a/webapp/titanembeds/database/guilds.py b/webapp/titanembeds/database/guilds.py index 537afc9..6d6b956 100644 --- a/webapp/titanembeds/database/guilds.py +++ b/webapp/titanembeds/database/guilds.py @@ -11,6 +11,7 @@ class Guilds(db.Model): guest_icon = db.Column(db.String(255), default=None) # Guest icon url, None if unset chat_links = db.Column(db.Boolean(), nullable=False, default=1) # If users can post links bracket_links = db.Column(db.Boolean(), nullable=False, default=1) # If appending brackets to links to prevent embed + unauth_captcha = db.Column(db.Boolean(), nullable=False, server_default="1")# Enforce captcha on guest users mentions_limit = db.Column(db.Integer, nullable=False, default=11) # If there is a limit on the number of mentions in a msg roles = db.Column(db.Text().with_variant(db.Text(4294967295), 'mysql'), nullable=False) # Guild Roles channels = db.Column(db.Text().with_variant(db.Text(4294967295), 'mysql'), nullable=False) # Guild channels @@ -29,6 +30,7 @@ class Guilds(db.Model): self.guest_icon = None self.chat_links = True self.bracket_links = True + self.unauth_captcha = True self.mentions_limit = -1 # -1 = unlimited mentions self.roles = roles self.channels = channels diff --git a/webapp/titanembeds/static/js/administrate_guild.js b/webapp/titanembeds/static/js/administrate_guild.js index 041f413..1af3c9f 100644 --- a/webapp/titanembeds/static/js/administrate_guild.js +++ b/webapp/titanembeds/static/js/administrate_guild.js @@ -76,6 +76,15 @@ $("#guest_icon").keyup(function(event){ } }); +$('#unauth_captcha').change(function() { + var pathname = window.location.pathname; + var checked = $(this).is(':checked') + var payload = {"unauth_captcha": checked} + $.post(pathname, payload, function(data) { + Materialize.toast('Updated Guest User Captcha setting!', 2000) + }); +}); + function initiate_ban(guild_id, user_id) { var reason = prompt("Please enter your reason for ban"); var payload = { diff --git a/webapp/titanembeds/static/js/embed.js b/webapp/titanembeds/static/js/embed.js index d441cfa..35c69cd 100644 --- a/webapp/titanembeds/static/js/embed.js +++ b/webapp/titanembeds/static/js/embed.js @@ -14,6 +14,7 @@ /* global grecaptcha */ /* global hljs */ /* global linkify */ +/* global unauth_captcha_enabled */ (function () { const theme_options = ["DiscordDark", "BetterTitan"]; // All the avaliable theming names @@ -1084,7 +1085,11 @@ } if($(this).val().length >= 2 && $(this).val().length <= 32) { $("#custom_username_field").blur(); - $('#recaptchamodal').modal('open'); + if (unauth_captcha_enabled) { + $('#recaptchamodal').modal('open'); + } else { + submit_unauthenticated_captcha(); + } } } }); diff --git a/webapp/titanembeds/templates/administrate_guild.html.j2 b/webapp/titanembeds/templates/administrate_guild.html.j2 index 393f9bc..b00d04b 100644 --- a/webapp/titanembeds/templates/administrate_guild.html.j2 +++ b/webapp/titanembeds/templates/administrate_guild.html.j2 @@ -100,6 +100,19 @@ +
+ +

Toggle Guest Captcha

+

Prevent bots from logging into your embed

+
+ +
+

Message mentions limit

diff --git a/webapp/titanembeds/templates/embed.html.j2 b/webapp/titanembeds/templates/embed.html.j2 index 3adf969..cd79396 100644 --- a/webapp/titanembeds/templates/embed.html.j2 +++ b/webapp/titanembeds/templates/embed.html.j2 @@ -238,6 +238,7 @@ const guild_id = "{{ guild_id }}"; const bot_client_id = "{{ client_id }}"; const visitors_enabled = {% if visitors_enabled %}true{% else %}false{% endif %}; + const unauth_captcha_enabled = {% if unauth_captcha_enabled %}true{% else %}false{% endif %} diff --git a/webapp/titanembeds/utils.py b/webapp/titanembeds/utils.py index 87e9e7f..3a5ef71 100644 --- a/webapp/titanembeds/utils.py +++ b/webapp/titanembeds/utils.py @@ -287,5 +287,9 @@ def guild_webhooks_enabled(guild_id): return False return bot_can_create_webhooks(dbguild) +def guild_unauthcaptcha_enabled(guild_id): + dbguild = db.session.query(Guilds).filter(Guilds.guild_id == guild_id).first() + return dbguild.unauth_captcha + rate_limiter = Limiter(key_func=get_client_ipaddr) # Default limit by ip address socketio = SocketIO() \ No newline at end of file