mirror of
				https://github.com/TitanEmbeds/Titan.git
				synced 2025-11-04 07:47:10 +01:00 
			
		
		
		
	Add recaptcha v2 to verify guest logins (#55)
This commit is contained in:
		
				
					committed by
					
						
						GitHub
					
				
			
			
				
	
			
			
			
						parent
						
							f6b354f10d
						
					
				
				
					commit
					392c7ae69e
				
			@@ -3,12 +3,14 @@ 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.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
 | 
			
		||||
from flask_socketio import emit
 | 
			
		||||
from sqlalchemy import and_
 | 
			
		||||
import random
 | 
			
		||||
import json
 | 
			
		||||
import datetime
 | 
			
		||||
import re
 | 
			
		||||
import requests
 | 
			
		||||
from config import config
 | 
			
		||||
 | 
			
		||||
api = Blueprint("api", __name__)
 | 
			
		||||
@@ -270,6 +272,17 @@ def post():
 | 
			
		||||
    response.status_code = status_code
 | 
			
		||||
    return response
 | 
			
		||||
 | 
			
		||||
def verify_captcha_request(captcha_response, ip_address):
 | 
			
		||||
    payload = {
 | 
			
		||||
        "secret": config["recaptcha-secret-key"],
 | 
			
		||||
        "response": captcha_response,
 | 
			
		||||
        "remoteip": ip_address,
 | 
			
		||||
    }
 | 
			
		||||
    if app.config["DEBUG"]:
 | 
			
		||||
        del payload["remoteip"]
 | 
			
		||||
    r = requests.post("https://www.google.com/recaptcha/api/siteverify", data=payload).json()
 | 
			
		||||
    return r["success"]
 | 
			
		||||
 | 
			
		||||
@api.route("/create_unauthenticated_user", methods=["POST"])
 | 
			
		||||
@rate_limiter.limit("3 per 30 minute", key_func=guild_ratelimit_key)
 | 
			
		||||
def create_unauthenticated_user():
 | 
			
		||||
@@ -278,6 +291,9 @@ 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):
 | 
			
		||||
 
 | 
			
		||||
@@ -65,11 +65,13 @@ def guild_embed(guild_id):
 | 
			
		||||
        customcss = get_custom_css()
 | 
			
		||||
        return render_template("embed.html.j2",
 | 
			
		||||
            login_greeting=get_logingreeting(),
 | 
			
		||||
            guild_id=guild_id, guild=guild_dict,
 | 
			
		||||
            guild_id=guild_id,
 | 
			
		||||
            guild=guild_dict,
 | 
			
		||||
            generate_guild_icon=generate_guild_icon_url,
 | 
			
		||||
            unauth_enabled=guild_query_unauth_users_bool(guild_id),
 | 
			
		||||
            visitors_enabled=guild_accepts_visitors(guild_id),
 | 
			
		||||
            client_id=config['client-id'],
 | 
			
		||||
            recaptcha_site_key=config["recaptcha-site-key"],
 | 
			
		||||
            css=customcss,
 | 
			
		||||
            cssvariables=parse_css_variable(customcss)
 | 
			
		||||
        )
 | 
			
		||||
 
 | 
			
		||||
@@ -490,6 +490,11 @@ p.mentioned span.chatmessage {
 | 
			
		||||
  top: -5px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#google-recaptcha {
 | 
			
		||||
  margin: 0 auto;
 | 
			
		||||
  width: 302px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* CSS Variables */
 | 
			
		||||
:root {
 | 
			
		||||
  /*--<var>: <value>*/
 | 
			
		||||
 
 | 
			
		||||
@@ -11,6 +11,7 @@
 | 
			
		||||
/* global io */
 | 
			
		||||
/* global twemoji */
 | 
			
		||||
/* global jQuery */
 | 
			
		||||
/* global grecaptcha */
 | 
			
		||||
 | 
			
		||||
(function () {
 | 
			
		||||
    const theme_options = ["DiscordDark", "BetterTitan"]; // All the avaliable theming names
 | 
			
		||||
@@ -73,12 +74,12 @@
 | 
			
		||||
        return funct.promise();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function create_unauthenticated_user(username) {
 | 
			
		||||
    function create_unauthenticated_user(username, captchaResponse) {
 | 
			
		||||
        var funct = $.ajax({
 | 
			
		||||
            method: "POST",
 | 
			
		||||
            dataType: "json",
 | 
			
		||||
            url: "/api/create_unauthenticated_user",
 | 
			
		||||
            data: {"username": username, "guild_id": guild_id}
 | 
			
		||||
            data: {"username": username, "guild_id": guild_id, "captcha_response": captchaResponse}
 | 
			
		||||
        });
 | 
			
		||||
        return funct.promise();
 | 
			
		||||
    }
 | 
			
		||||
@@ -142,6 +143,14 @@
 | 
			
		||||
          }
 | 
			
		||||
        );
 | 
			
		||||
        $('#loginmodal').modal('open');
 | 
			
		||||
        $("#recaptchamodal").modal({
 | 
			
		||||
            dismissible: true,
 | 
			
		||||
            opacity: .5,
 | 
			
		||||
            inDuration: 400,
 | 
			
		||||
            outDuration: 400,
 | 
			
		||||
            startingTop: '40%',
 | 
			
		||||
            endingTop: '30%',
 | 
			
		||||
        });
 | 
			
		||||
        $("#userembedmodal").modal({
 | 
			
		||||
            dismissible: true,
 | 
			
		||||
            opacity: .5,
 | 
			
		||||
@@ -948,7 +957,7 @@
 | 
			
		||||
        lock_login_fields();
 | 
			
		||||
        wait_for_discord_login();
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
    $("#custom_username_field").keyup(function(event){
 | 
			
		||||
        if (event.keyCode == 13) {
 | 
			
		||||
            if (!(new RegExp(/^[a-z\d\-_\s]+$/i).test($(this).val()))) {
 | 
			
		||||
@@ -956,28 +965,36 @@
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
            if($(this).val().length >= 2 && $(this).val().length <= 32) {
 | 
			
		||||
                lock_login_fields();
 | 
			
		||||
                var usr = create_unauthenticated_user($(this).val());
 | 
			
		||||
                usr.done(function(data) {
 | 
			
		||||
                    setVisitorMode(false);
 | 
			
		||||
                    initialize_embed();
 | 
			
		||||
                });
 | 
			
		||||
                usr.fail(function(data) {
 | 
			
		||||
                    if (data.status == 429) {
 | 
			
		||||
                        Materialize.toast('Sorry! You are allowed to log in as a guest three times in a span of 30 minutes.', 10000);
 | 
			
		||||
                    } else if (data.status == 403) {
 | 
			
		||||
                        Materialize.toast('Authentication error! You have been banned.', 10000);
 | 
			
		||||
                    } else if (data.status == 406) {
 | 
			
		||||
                        Materialize.toast('Illegal username provided! Only alphanumeric, spaces, dashes, and underscores allowed in usernames.', 10000);
 | 
			
		||||
                    } else if (data.status == 422) {
 | 
			
		||||
                        Materialize.toast("Attempting to add you into the server has failed. Either you are banned, reached 100 servers in Discord, or something else bad has happened.", 10000);
 | 
			
		||||
                    }
 | 
			
		||||
                    unlock_login_fields();
 | 
			
		||||
                    setVisitorMode(true);
 | 
			
		||||
                });
 | 
			
		||||
                $("#custom_username_field").blur();
 | 
			
		||||
                $('#recaptchamodal').modal('open');
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    $("#submit-unauthenticated-captcha-btn").click(function(){
 | 
			
		||||
        lock_login_fields();
 | 
			
		||||
        var usr = create_unauthenticated_user($("#custom_username_field").val(), grecaptcha.getResponse());
 | 
			
		||||
        usr.done(function(data) {
 | 
			
		||||
            grecaptcha.reset();
 | 
			
		||||
            setVisitorMode(false);
 | 
			
		||||
            initialize_embed();
 | 
			
		||||
        });
 | 
			
		||||
        usr.fail(function(data) {
 | 
			
		||||
            if (data.status == 429) {
 | 
			
		||||
                Materialize.toast('Sorry! You are allowed to log in as a guest three times in a span of 30 minutes.', 10000);
 | 
			
		||||
            } else if (data.status == 403) {
 | 
			
		||||
                Materialize.toast('Authentication error! You have been banned.', 10000);
 | 
			
		||||
            } else if (data.status == 406) {
 | 
			
		||||
                Materialize.toast('Illegal username provided! Only alphanumeric, spaces, dashes, and underscores allowed in usernames.', 10000);
 | 
			
		||||
            } else if (data.status == 422) {
 | 
			
		||||
                Materialize.toast("Attempting to add you into the server has failed. Either you are banned, reached 100 servers in Discord, or something else bad has happened.", 10000);
 | 
			
		||||
            } else if (data.status == 412) {
 | 
			
		||||
                Materialize.toast("reCAPTCHA reponse has failed. Try again?", 10000);
 | 
			
		||||
            }
 | 
			
		||||
            unlock_login_fields();
 | 
			
		||||
            setVisitorMode(true);
 | 
			
		||||
        });
 | 
			
		||||
    });
 | 
			
		||||
    
 | 
			
		||||
    $("#change_username_field").keyup(function(event){
 | 
			
		||||
        if (event.keyCode == 13) {
 | 
			
		||||
@@ -1283,3 +1300,8 @@
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
})();
 | 
			
		||||
 | 
			
		||||
function submit_unauthenticated_captcha() { // To be invoked when recaptcha is completed
 | 
			
		||||
    $('#recaptchamodal').modal('close');
 | 
			
		||||
    $("#submit-unauthenticated-captcha-btn").click();
 | 
			
		||||
}
 | 
			
		||||
@@ -18,6 +18,7 @@
 | 
			
		||||
 | 
			
		||||
    <title>{{ guild['name'] }} - Embed - Titan Embeds for Discord</title>
 | 
			
		||||
    {% include 'google_analytics.html.j2' %}
 | 
			
		||||
    <script src='https://www.google.com/recaptcha/api.js'></script>
 | 
			
		||||
    
 | 
			
		||||
    <style id="user-defined-css">
 | 
			
		||||
      {% if css is not none %}
 | 
			
		||||
@@ -145,6 +146,14 @@
 | 
			
		||||
      </div>
 | 
			
		||||
    </div>
 | 
			
		||||
    
 | 
			
		||||
    <div id="recaptchamodal" class="modal">
 | 
			
		||||
      <div class="modal-content">
 | 
			
		||||
        <h4 class="center-align">Just one more step...</h4>
 | 
			
		||||
        <div id="google-recaptcha" class="g-recaptcha" data-sitekey="{{ recaptcha_site_key }}" data-callback="submit_unauthenticated_captcha"></div>
 | 
			
		||||
        <input type="hidden" id="submit-unauthenticated-captcha-btn" />
 | 
			
		||||
      </div>
 | 
			
		||||
    </div>
 | 
			
		||||
    
 | 
			
		||||
    <div id="emoji-picker">
 | 
			
		||||
      <div id="emoji-picker-content">
 | 
			
		||||
        <div class="row">
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user