Advertisement
Guest User

Untitled

a guest
Mar 6th, 2025
44
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 5.29 KB | None | 0 0
  1. import logging
  2.  
  3. import requests
  4. from quart import current_app, request
  5. from markupsafe import Markup
  6. from wtforms import ValidationError
  7. from wtforms.fields import HiddenField
  8. from wtforms.widgets import HiddenInput
  9. import json
  10.  
  11. logger = logging.getLogger(__name__)
  12.  
  13. JSONEncoder = json.JSONEncoder
  14.  
  15. RECAPTCHA_TEMPLATE = '''
  16. <script src='https://www.google.com/recaptcha/api.js?render={public_key}&onload=executeRecaptcha{action}' async defer></script>
  17. <script>
  18.  var executeRecaptcha{action} = function() {{
  19.    console.log("grecaptcha is ready!");
  20.    grecaptcha.execute('{public_key}', {{action: '{action}'}}).then(function(token) {{
  21.      console.log(token);
  22.      document.getElementById("{field_name}").value = token;
  23.    }});
  24.  }};
  25. </script>
  26. <input type="hidden" id="{field_name}" name="{field_name}">
  27. '''
  28.  
  29. RECAPTCHA_TEMPLATE_MANUAL = '''
  30. <script src='https://www.google.com/recaptcha/api.js?render={public_key}' async defer></script>
  31. <script>
  32.  var executeRecaptcha{action} = function() {{
  33.    console.log("executeRecaptcha{action}() is called!");
  34.    grecaptcha.ready(function() {{
  35.      console.log("grecaptcha is ready!");
  36.      grecaptcha.execute('{public_key}', {{action: '{action}'}}).then(function(token) {{
  37.        console.log(token);
  38.        document.getElementById("{field_name}").value = token;
  39.      }});
  40.    }});
  41.  }};
  42. </script>
  43. <input type="hidden" id="{field_name}" name="{field_name}">
  44. '''
  45.  
  46. RECAPTCHA_VERIFY_SERVER = 'https://www.google.com/recaptcha/api/siteverify'
  47. RECAPTCHA_ERROR_CODES = {
  48.     'missing-input-secret': 'The secret parameter is missing.',
  49.     'invalid-input-secret': 'The secret parameter is invalid or malformed.',
  50.     'missing-input-response': 'The response parameter is missing.',
  51.     'invalid-input-response': 'The response parameter is invalid or malformed.'
  52. }
  53.  
  54.  
  55. class Recaptcha3Validator(object):
  56.     """Validates a ReCaptcha."""
  57.  
  58.     def __init__(self, message=None):
  59.         if message is None:
  60.             message = "Please verify that you are not a robot."
  61.         self.message = message
  62.  
  63.     def __call__(self, form, field):
  64.         if current_app.testing:
  65.             return True
  66.  
  67.         token = field.data
  68.         if not token:
  69.             logger.warning("Token is not ready or incorrect configuration (check JavaScript error log).")
  70.             raise ValidationError(field.gettext(self.message))
  71.  
  72.         remote_ip = request.remote_addr
  73.         if not Recaptcha3Validator._validate_recaptcha(field, token, remote_ip):
  74.             field.recaptcha_error = 'incorrect-captcha-sol'
  75.             raise ValidationError(field.gettext(self.message))
  76.  
  77.     @staticmethod
  78.     def _validate_recaptcha(field, response, remote_addr):
  79.         """Performs the actual validation."""
  80.         try:
  81.             private_key = current_app.config['RECAPTCHA3_PRIVATE_KEY']
  82.         except KeyError:
  83.             raise RuntimeError("RECAPTCHA3_PRIVATE_KEY is not set in app config.")
  84.  
  85.         data = {
  86.             'secret': private_key,
  87.             'remoteip': remote_addr,
  88.             'response': response
  89.         }
  90.  
  91.         http_response = requests.post(RECAPTCHA_VERIFY_SERVER, data)
  92.         if http_response.status_code != 200:
  93.             return False
  94.  
  95.         json_resp = http_response.json()
  96.         if json_resp["success"] and json_resp["action"] == field.action and json_resp["score"] > field.score_threshold:
  97.             logger.info(json_resp)
  98.             return True
  99.         else:
  100.             logger.warning(json_resp)
  101.  
  102.         for error in json_resp.get("error-codes", []):
  103.             if error in RECAPTCHA_ERROR_CODES:
  104.                 raise ValidationError(RECAPTCHA_ERROR_CODES[error])
  105.  
  106.         return False
  107.  
  108.  
  109. class Recaptcha3Widget(HiddenInput):
  110.  
  111.     def __call__(self, field, **kwargs):
  112.         """Returns the recaptcha input HTML."""
  113.         public_key_name = 'RECAPTCHA3_PUBLIC_KEY'
  114.         try:
  115.             public_key = current_app.config[public_key_name]
  116.         except KeyError:
  117.             raise RuntimeError(f"{public_key_name} is not set in app config.")
  118.  
  119.         return Markup(
  120.                 (RECAPTCHA_TEMPLATE if field.execute_on_load else RECAPTCHA_TEMPLATE_MANUAL).format(
  121.                         public_key=public_key, action=field.action, field_name=field.name))
  122.  
  123.  
  124. class Recaptcha3Field(HiddenField):
  125.     widget = Recaptcha3Widget()
  126.  
  127.     # error message if recaptcha validation fails
  128.     recaptcha_error = None
  129.  
  130.     def __init__(self, action, score_threshold=0.5, execute_on_load=True, validators=None, **kwargs):
  131.         '''If execute_on_load is False, recaptcha.execute needs to be manually bound to an event to obtain token,
  132.        the JavaScript function to call is executeRecaptcha{action}, e.g. onsubmit="executeRecaptchaSignIn" '''
  133.         if not action:
  134.             # TODO: more validation on action, see https://developers.google.com/recaptcha/docs/v3#actions
  135.             #   "actions may only contain alphanumeric characters and slashes, and must not be user-specific"
  136.             raise RuntimeError("action must not be none or empty.")
  137.  
  138.         self.action = action
  139.         self.execute_on_load = execute_on_load
  140.         self.score_threshold = score_threshold
  141.         validators = validators or [Recaptcha3Validator()]
  142.         super(Recaptcha3Field, self).__init__(validators=validators, **kwargs)
  143.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement